Add appeals (#17364)

* Add appeals

* Add ability to reject appeals and ability to browse pending appeals in admin UI

* Add strikes to account page in settings

* Various fixes and improvements

- Add separate notification setting for appeals, separate from reports
- Fix style of links in report/strike header
- Change approving an appeal to not restore statuses (due to federation complexities)
- Change style of successfully appealed strikes on account settings page
- Change account settings page to only show unappealed or recently appealed strikes

* Change appealed_at to overruled_at

* Fix missing method error
This commit is contained in:
Eugen Rochko 2022-02-14 21:27:53 +01:00 committed by GitHub
parent 5be705e1e0
commit 564efd0651
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 1212 additions and 93 deletions

View file

@ -1,7 +0,0 @@
.speech-bubble
.speech-bubble__bubble
= simple_format(h(account_moderation_note.content))
.speech-bubble__owner
= admin_account_link_to account_moderation_note.account
%time.formatted{ datetime: account_moderation_note.created_at.iso8601 }= l account_moderation_note.created_at
= table_link_to 'trash', t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note)

View file

@ -1,6 +1,24 @@
.speech-bubble.warning
.speech-bubble__bubble
= Formatter.instance.linkify(account_warning.text)
.speech-bubble__owner
= admin_account_link_to account_warning.account
%time.formatted{ datetime: account_warning.created_at.iso8601 }= l account_warning.created_at
= link_to disputes_strike_path(account_warning), class: ['log-entry', account_warning.overruled? && 'log-entry--inactive'] do
.log-entry__header
.log-entry__avatar
= image_tag account_warning.target_account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
.log-entry__content
.log-entry__title
= t(account_warning.action, scope: 'admin.strikes.actions', name: content_tag(:span, account_warning.account.username, class: 'username'), target: content_tag(:span, account_warning.target_account.acct, class: 'target')).html_safe
.log-entry__timestamp
%time.formatted{ datetime: account_warning.created_at.iso8601 }
= l(account_warning.created_at)
- if account_warning.report_id.present?
·
= t('admin.reports.title', id: account_warning.report_id)
- if account_warning.overruled?
·
%span.positive-hint= t('admin.strikes.appeal_approved')
- elsif account_warning.appeal&.pending?
·
%span.warning-hint= t('admin.strikes.appeal_pending')
- elsif account_warning.appeal&.rejected?
·
%span.negative-hint= t('admin.strikes.appeal_rejected')

View file

@ -246,18 +246,29 @@
%hr.spacer/
- unless @warnings.empty?
= render @warnings
%h3= t 'admin.accounts.previous_strikes'
%p= t('admin.accounts.previous_strikes_description_html', count: @account.previous_strikes_count)
.account-strikes
= render @warnings
%hr.spacer/
= render @moderation_notes
%h3= t 'admin.reports.notes.title'
%p= t 'admin.reports.notes_description_html'
.report-notes
= render partial: 'admin/report_notes/report_note', collection: @moderation_notes
= simple_form_for @account_moderation_note, url: admin_account_moderation_notes_path do |f|
= render 'shared/error_messages', object: @account_moderation_note
= f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
= f.hidden_field :target_account_id
.field-group
= f.input :content, placeholder: t('admin.reports.notes.placeholder'), rows: 6
.actions
= f.button :button, t('admin.account_moderation_notes.create'), type: :submit

View file

@ -46,6 +46,9 @@
%span= t('admin.dashboard.pending_tags_html', count: @pending_tags_count)
= fa_icon 'chevron-right fw'
= link_to admin_disputes_appeals_path(status: 'pending'), class: 'dashboard__quick-access' do
%span= t('admin.dashboard.pending_appeals_html', count: @pending_appeals_count)
= fa_icon 'chevron-right fw'
.dashboard__item
= react_admin_component :dimension, dimension: 'sources', start_at: @time_period.first, end_at: @time_period.last, limit: 8, label: t('admin.dashboard.sources')

View file

@ -0,0 +1,21 @@
= link_to disputes_strike_path(appeal.strike), class: ['log-entry', appeal.approved? && 'log-entry--inactive'] do
.log-entry__header
.log-entry__avatar
= image_tag appeal.account.avatar.url(:original), alt: '', width: 40, height: 40, class: 'avatar'
.log-entry__content
.log-entry__title
= t(appeal.strike.action, scope: 'admin.strikes.actions', name: content_tag(:span, appeal.strike.account.username, class: 'username'), target: content_tag(:span, appeal.account.acct, class: 'target')).html_safe
.log-entry__timestamp
%time.formatted{ datetime: appeal.strike.created_at.iso8601 }
= l(appeal.strike.created_at)
- if appeal.strike.report_id.present?
·
= t('admin.reports.title', id: appeal.strike.report_id)
·
- if appeal.approved?
%span.positive-hint= t('admin.strikes.appeal_approved')
- elsif appeal.rejected?
%span.negative-hint= t('admin.strikes.appeal_rejected')
- else
%span.warning-hint= t('admin.strikes.appeal_pending')

View file

@ -0,0 +1,22 @@
- content_for :page_title do
= t('admin.disputes.appeals.title')
- content_for :header_tags do
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
.filters
.filter-subset
%strong= t('admin.tags.review')
%ul
%li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Appeal.pending.count})"], ' '), status: 'pending'
%li= filter_link_to t('admin.trends.approved'), status: 'approved'
%li= filter_link_to t('admin.trends.rejected'), status: 'rejected'
- if @appeals.empty?
%div.muted-hint.center-text
= t 'admin.disputes.appeals.empty'
- else
.announcements-list
= render partial: 'appeal', collection: @appeals
= paginate @appeals

View file

@ -3,7 +3,7 @@
.report-notes__item__header
%span.username
= link_to display_name(report_note.account), admin_account_path(report_note.account_id)
= link_to report_note.account.username, admin_account_path(report_note.account_id)
%time{ datetime: report_note.created_at.iso8601, title: l(report_note.created_at) }
- if report_note.created_at.today?
= t('admin.report_notes.today_at', time: l(report_note.created_at, format: :time))

View file

@ -57,7 +57,7 @@
.report-header__details__item__header
%strong= t('admin.accounts.strikes')
.report-header__details__item__content
= @report.target_account.strikes.count
= @report.target_account.previous_strikes_count
.report-header__details
.report-header__details__item