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:
parent
5be705e1e0
commit
564efd0651
60 changed files with 1212 additions and 93 deletions
|
@ -1,25 +1,5 @@
|
|||
{
|
||||
"ignored_warnings": [
|
||||
{
|
||||
"warning_type": "SQL Injection",
|
||||
"warning_code": 0,
|
||||
"fingerprint": "04dbbc249b989db2e0119bbb0f59c9818e12889d2b97c529cdc0b1526002ba4b",
|
||||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/report.rb",
|
||||
"line": 113,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "Admin::ActionLog.from(\"(#{[Admin::ActionLog.where(:target_type => \"Report\", :target_id => id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Account\", :target_id => target_account_id, :created_at => ((created_at..updated_at))).unscope(:order), Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)].map do\n \"(#{query.to_sql})\"\n end.join(\" UNION ALL \")}) AS admin_action_logs\")",
|
||||
"render_path": null,
|
||||
"location": {
|
||||
"type": "method",
|
||||
"class": "Report",
|
||||
"method": "history"
|
||||
},
|
||||
"user_input": "Admin::ActionLog.where(:target_type => \"Status\", :target_id => status_ids, :created_at => ((created_at..updated_at))).unscope(:order)",
|
||||
"confidence": "High",
|
||||
"note": ""
|
||||
},
|
||||
{
|
||||
"warning_type": "SQL Injection",
|
||||
"warning_code": 0,
|
||||
|
@ -27,7 +7,7 @@
|
|||
"check_name": "SQL",
|
||||
"message": "Possible SQL injection",
|
||||
"file": "app/models/status.rb",
|
||||
"line": 100,
|
||||
"line": 104,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/sql_injection/",
|
||||
"code": "result.joins(\"INNER JOIN statuses_tags t#{id} ON t#{id}.status_id = statuses.id AND t#{id}.tag_id = #{id}\")",
|
||||
"render_path": null,
|
||||
|
@ -107,7 +87,7 @@
|
|||
"check_name": "PermitAttributes",
|
||||
"message": "Potentially dangerous key allowed for mass assignment",
|
||||
"file": "app/controllers/api/v1/admin/reports_controller.rb",
|
||||
"line": 78,
|
||||
"line": 90,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
||||
"code": "params.permit(:resolved, :account_id, :target_account_id)",
|
||||
"render_path": null,
|
||||
|
@ -140,6 +120,36 @@
|
|||
"confidence": "Medium",
|
||||
"note": ""
|
||||
},
|
||||
{
|
||||
"warning_type": "Cross-Site Scripting",
|
||||
"warning_code": 2,
|
||||
"fingerprint": "afad51718ae373b2f19d2513029fd2afccf58b9148e475934bc6a162ee33c352",
|
||||
"check_name": "CrossSiteScripting",
|
||||
"message": "Unescaped model attribute",
|
||||
"file": "app/views/admin/disputes/appeals/_appeal.html.haml",
|
||||
"line": 7,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/cross_site_scripting",
|
||||
"code": "t((Unresolved Model).new.strike.action, :scope => \"admin.strikes.actions\", :name => content_tag(:span, (Unresolved Model).new.strike.account.username, :class => \"username\"), :target => content_tag(:span, (Unresolved Model).new.account.acct, :class => \"target\"))",
|
||||
"render_path": [
|
||||
{
|
||||
"type": "template",
|
||||
"name": "admin/disputes/appeals/index",
|
||||
"line": 16,
|
||||
"file": "app/views/admin/disputes/appeals/index.html.haml",
|
||||
"rendered": {
|
||||
"name": "admin/disputes/appeals/_appeal",
|
||||
"file": "app/views/admin/disputes/appeals/_appeal.html.haml"
|
||||
}
|
||||
}
|
||||
],
|
||||
"location": {
|
||||
"type": "template",
|
||||
"template": "admin/disputes/appeals/_appeal"
|
||||
},
|
||||
"user_input": "(Unresolved Model).new.strike",
|
||||
"confidence": "Weak",
|
||||
"note": ""
|
||||
},
|
||||
{
|
||||
"warning_type": "Redirect",
|
||||
"warning_code": 18,
|
||||
|
@ -194,7 +204,7 @@
|
|||
{
|
||||
"type": "template",
|
||||
"name": "admin/trends/links/index",
|
||||
"line": 37,
|
||||
"line": 39,
|
||||
"file": "app/views/admin/trends/links/index.html.haml",
|
||||
"rendered": {
|
||||
"name": "admin/trends/links/_preview_card",
|
||||
|
@ -213,13 +223,13 @@
|
|||
{
|
||||
"warning_type": "Mass Assignment",
|
||||
"warning_code": 105,
|
||||
"fingerprint": "e867661b2c9812bc8b75a5df12b28e2a53ab97015de0638b4e732fe442561b28",
|
||||
"fingerprint": "f9de0ca4b04ae4b51b74d98db14dcbb6dae6809e627b58e711019cf9b4a47866",
|
||||
"check_name": "PermitAttributes",
|
||||
"message": "Potentially dangerous key allowed for mass assignment",
|
||||
"file": "app/controllers/api/v1/reports_controller.rb",
|
||||
"line": 36,
|
||||
"link": "https://brakemanscanner.org/docs/warning_types/mass_assignment/",
|
||||
"code": "params.permit(:account_id, :comment, :forward, :status_ids => ([]))",
|
||||
"code": "params.permit(:account_id, :comment, :category, :forward, :status_ids => ([]), :rule_ids => ([]))",
|
||||
"render_path": null,
|
||||
"location": {
|
||||
"type": "method",
|
||||
|
@ -231,6 +241,6 @@
|
|||
"note": ""
|
||||
}
|
||||
],
|
||||
"updated": "2021-11-14 05:26:09 +0100",
|
||||
"brakeman_version": "5.1.2"
|
||||
"updated": "2022-02-13 02:24:12 +0100",
|
||||
"brakeman_version": "5.2.1"
|
||||
}
|
||||
|
|
|
@ -94,7 +94,6 @@ en:
|
|||
account_moderation_notes:
|
||||
create: Leave note
|
||||
created_msg: Moderation note successfully created!
|
||||
delete: Delete
|
||||
destroyed_msg: Moderation note successfully destroyed!
|
||||
accounts:
|
||||
add_email_domain_block: Block e-mail domain
|
||||
|
@ -163,6 +162,11 @@ en:
|
|||
not_subscribed: Not subscribed
|
||||
pending: Pending review
|
||||
perform_full_suspension: Suspend
|
||||
previous_strikes: Previous strikes
|
||||
previous_strikes_description_html:
|
||||
one: This account has <strong>one</strong> strike.
|
||||
other: This account has <strong>%{count}</strong> strikes.
|
||||
zero: This account is <strong>in good standing</strong>.
|
||||
promote: Promote
|
||||
protocol: Protocol
|
||||
public: Public
|
||||
|
@ -227,6 +231,7 @@ en:
|
|||
whitelisted: Allowed for federation
|
||||
action_logs:
|
||||
action_types:
|
||||
approve_appeal: Approve Appeal
|
||||
approve_user: Approve User
|
||||
assigned_to_self_report: Assign Report
|
||||
change_email_user: Change E-mail for User
|
||||
|
@ -258,6 +263,7 @@ en:
|
|||
enable_user: Enable User
|
||||
memorialize_account: Memorialize Account
|
||||
promote_user: Promote User
|
||||
reject_appeal: Reject Appeal
|
||||
reject_user: Reject User
|
||||
remove_avatar_user: Remove Avatar
|
||||
reopen_report: Reopen Report
|
||||
|
@ -276,6 +282,7 @@ en:
|
|||
update_domain_block: Update Domain Block
|
||||
update_status: Update Post
|
||||
actions:
|
||||
approve_appeal_html: "%{name} approved moderation decision appeal from %{target}"
|
||||
approve_user_html: "%{name} approved sign-up from %{target}"
|
||||
assigned_to_self_report_html: "%{name} assigned report %{target} to themselves"
|
||||
change_email_user_html: "%{name} changed the e-mail address of user %{target}"
|
||||
|
@ -307,6 +314,7 @@ en:
|
|||
enable_user_html: "%{name} enabled login for user %{target}"
|
||||
memorialize_account_html: "%{name} turned %{target}'s account into a memoriam page"
|
||||
promote_user_html: "%{name} promoted user %{target}"
|
||||
reject_appeal_html: "%{name} rejected moderation decision appeal from %{target}"
|
||||
reject_user_html: "%{name} rejected sign-up from %{target}"
|
||||
remove_avatar_user_html: "%{name} removed %{target}'s avatar"
|
||||
reopen_report_html: "%{name} reopened report %{target}"
|
||||
|
@ -385,6 +393,9 @@ en:
|
|||
media_storage: Media storage
|
||||
new_users: new users
|
||||
opened_reports: reports opened
|
||||
pending_appeals_html:
|
||||
one: "<strong>1</strong> pending appeal"
|
||||
other: "<strong>%{count}</strong> pending appeals"
|
||||
pending_reports_html:
|
||||
one: "<strong>1</strong> pending report"
|
||||
other: "<strong>%{count}</strong> pending reports"
|
||||
|
@ -402,6 +413,10 @@ en:
|
|||
top_languages: Top active languages
|
||||
top_servers: Top active servers
|
||||
website: Website
|
||||
disputes:
|
||||
appeals:
|
||||
empty: No appeals found.
|
||||
title: Appeals
|
||||
domain_allows:
|
||||
add_new: Allow federation with domain
|
||||
created_msg: Domain has been successfully allowed for federation
|
||||
|
@ -720,6 +735,16 @@ en:
|
|||
no_status_selected: No posts were changed as none were selected
|
||||
title: Account posts
|
||||
with_media: With media
|
||||
strikes:
|
||||
actions:
|
||||
delete_statuses: "%{name} deleted %{target}'s posts"
|
||||
disable: "%{name} froze %{target}'s account"
|
||||
none: "%{name} sent a warning to %{target}"
|
||||
sensitive: "%{name} marked %{target}'s account as sensitive"
|
||||
silence: "%{name} limited %{target}'s account"
|
||||
suspend: "%{name} suspended %{target}'s account"
|
||||
appeal_approved: Appealed
|
||||
appeal_pending: Appeal pending
|
||||
system_checks:
|
||||
database_schema_check:
|
||||
message_html: There are pending database migrations. Please run them to ensure the application behaves as expected
|
||||
|
@ -781,6 +806,17 @@ en:
|
|||
empty: You haven't defined any warning presets yet.
|
||||
title: Manage warning presets
|
||||
admin_mailer:
|
||||
new_appeal:
|
||||
actions:
|
||||
delete_statuses: to delete their posts
|
||||
disable: to freeze their account
|
||||
none: a warning
|
||||
sensitive: to mark their account as sensitive
|
||||
silence: to limit their account
|
||||
suspend: to suspend their account
|
||||
body: "%{target} is appealing a moderation decision by %{action_taken_by} from %{date}, which was %{type}. They wrote:"
|
||||
next_steps: You can approve the appeal to undo the moderation decision, or ignore it.
|
||||
subject: "%{username} is appealing a moderation decision on %{instance}"
|
||||
new_pending_account:
|
||||
body: The details of the new account are below. You can approve or reject this application.
|
||||
subject: New account up for review on %{instance} (%{username})
|
||||
|
@ -871,7 +907,6 @@ en:
|
|||
status:
|
||||
account_status: Account status
|
||||
confirming: Waiting for e-mail confirmation to be completed.
|
||||
functional: Your account is fully operational.
|
||||
pending: Your application is pending review by our staff. This may take some time. You will receive an e-mail if your application is approved.
|
||||
redirecting_to: Your account is inactive because it is currently redirecting to %{acct}.
|
||||
too_fast: Form submitted too fast, try again.
|
||||
|
@ -937,6 +972,32 @@ en:
|
|||
directory: Profile directory
|
||||
explanation: Discover users based on their interests
|
||||
explore_mastodon: Explore %{title}
|
||||
disputes:
|
||||
strikes:
|
||||
action_taken: Action taken
|
||||
appeal: Appeal
|
||||
appeal_approved: This strike has been successfully appealed and is no longer valid
|
||||
appeal_rejected: The appeal has been rejected
|
||||
appeal_submitted_at: Appeal submitted
|
||||
appealed_msg: Your appeal has been submitted. If it is approved, you will be notified.
|
||||
appeals:
|
||||
submit: Submit appeal
|
||||
associated_report: Associated report
|
||||
created_at: Dated
|
||||
recipient: Addressed to
|
||||
status: 'Post #%{id}'
|
||||
status_removed: Post already removed from system
|
||||
title: "%{action} from %{date}"
|
||||
title_actions:
|
||||
delete_statuses: Post removal
|
||||
disable: Freezing of account
|
||||
none: Warning
|
||||
sensitive: Marking as sensitive of account
|
||||
silence: Limitation of account
|
||||
suspend: Suspension of account
|
||||
your_appeal_approved: Your appeal has been approved
|
||||
your_appeal_pending: You have submitted an appeal
|
||||
your_appeal_rejected: Your appeal has been rejected
|
||||
domain_validator:
|
||||
invalid_domain: is not a valid domain name
|
||||
errors:
|
||||
|
@ -1501,6 +1562,15 @@ en:
|
|||
recovery_instructions_html: If you ever lose access to your phone, you can use one of the recovery codes below to regain access to your account. <strong>Keep the recovery codes safe</strong>. For example, you may print them and store them with other important documents.
|
||||
webauthn: Security keys
|
||||
user_mailer:
|
||||
appeal_approved:
|
||||
action: Go to your account
|
||||
explanation: The appeal of the strike against your account on %{strike_date} that you submitted on %{appeal_date} has been approved. Your account is once again in good standing.
|
||||
subject: Your appeal from %{date} has been approved
|
||||
title: Appeal approved
|
||||
appeal_rejected:
|
||||
explanation: The appeal of the strike against your account on %{strike_date} that you submitted on %{appeal_date} has been rejected.
|
||||
subject: Your appeal from %{date} has been rejected
|
||||
title: Appeal rejected
|
||||
backup_ready:
|
||||
explanation: You requested a full backup of your Mastodon account. It's now ready for download!
|
||||
subject: Your archive is ready for download
|
||||
|
@ -1512,6 +1582,8 @@ en:
|
|||
subject: Please confirm attempted sign in
|
||||
title: Sign in attempt
|
||||
warning:
|
||||
appeal: Submit an appeal
|
||||
appeal_description: If you believe this is an error, you can submit an appeal to the staff of %{instance}.
|
||||
categories:
|
||||
spam: Spam
|
||||
violation: Content violates the following community guidelines
|
||||
|
@ -1523,7 +1595,6 @@ en:
|
|||
suspend: You can no longer use your account, and your profile and other data are no longer accessible. You can still login to request a backup of your data until the data is fully removed in about 30 days, but we will retain some basic data to prevent you from evading the suspension.
|
||||
get_in_touch: If you believe this is an error, you can reply to this e-mail to get in touch with the staff of %{instance}.
|
||||
reason: 'Reason:'
|
||||
review_server_policies: Review server policies
|
||||
statuses: 'Posts that have been found in violation:'
|
||||
subject:
|
||||
delete_statuses: Your posts on %{acct} have been removed
|
||||
|
|
|
@ -27,6 +27,8 @@ en:
|
|||
scheduled_at: Leave blank to publish the announcement immediately
|
||||
starts_at: Optional. In case your announcement is bound to a specific time range
|
||||
text: You can use post syntax. Please be mindful of the space the announcement will take up on the user's screen
|
||||
appeal:
|
||||
text: You can only appeal a strike once
|
||||
defaults:
|
||||
autofollow: People who sign up through the invite will automatically follow you
|
||||
avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
|
||||
|
@ -119,6 +121,8 @@ en:
|
|||
scheduled_at: Schedule publication
|
||||
starts_at: Start of event
|
||||
text: Announcement
|
||||
appeal:
|
||||
text: Explain why this decision should be reversed
|
||||
defaults:
|
||||
autofollow: Invite to follow your account
|
||||
avatar: Avatar
|
||||
|
@ -197,6 +201,7 @@ en:
|
|||
sign_up_requires_approval: Limit sign-ups
|
||||
severity: Rule
|
||||
notification_emails:
|
||||
appeal: Someone appeals a moderator decision
|
||||
digest: Send digest e-mails
|
||||
favourite: Someone favourited your post
|
||||
follow: Someone followed you
|
||||
|
@ -204,8 +209,8 @@ en:
|
|||
mention: Someone mentioned you
|
||||
pending_account: New account needs review
|
||||
reblog: Someone boosted your post
|
||||
report: A new report is submitted
|
||||
trending_tag: A new trend requires approval
|
||||
report: New report is submitted
|
||||
trending_tag: New trend requires review
|
||||
rule:
|
||||
text: Rule
|
||||
tag:
|
||||
|
|
|
@ -20,7 +20,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
|||
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_url, if: -> { current_user.functional? }
|
||||
|
||||
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_url do |s|
|
||||
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities}
|
||||
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
|
||||
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_url, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
|
||||
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
|
||||
end
|
||||
|
@ -41,7 +41,7 @@ SimpleNavigation::Configuration.run do |navigation|
|
|||
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |s|
|
||||
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url
|
||||
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports}
|
||||
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts}
|
||||
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes}
|
||||
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path
|
||||
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}
|
||||
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: whitelist_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.admin? }
|
||||
|
|
|
@ -164,6 +164,12 @@ Rails.application.routes.draw do
|
|||
resources :login_activities, only: [:index]
|
||||
end
|
||||
|
||||
namespace :disputes do
|
||||
resources :strikes, only: [:show] do
|
||||
resource :appeal, only: [:create]
|
||||
end
|
||||
end
|
||||
|
||||
resources :media, only: [:show] do
|
||||
get :player
|
||||
end
|
||||
|
@ -324,6 +330,15 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
namespace :disputes do
|
||||
resources :appeals, only: [:index] do
|
||||
member do
|
||||
post :approve
|
||||
post :reject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
get '/admin', to: redirect('/admin/dashboard', status: 302)
|
||||
|
|
|
@ -48,6 +48,7 @@ defaults: &defaults
|
|||
report: true
|
||||
pending_account: true
|
||||
trending_tag: true
|
||||
appeal: true
|
||||
interactions:
|
||||
must_be_follower: false
|
||||
must_be_following: false
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue