Skip to content

Commit fcf3aee

Browse files
Gargronhiyuki2578
authored andcommitted
Add moderation API (mastodon#9387)
Fix mastodon#8580 Fix mastodon#7143
1 parent d9b5ff8 commit fcf3aee

18 files changed

Lines changed: 735 additions & 1 deletion

app/controllers/admin/accounts_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def filter_params
127127
:by_domain,
128128
:active,
129129
:pending,
130+
:disabled,
130131
:silenced,
131132
:suspended,
132133
:username,
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::Admin::AccountActionsController < Api::BaseController
4+
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }
5+
before_action :require_staff!
6+
before_action :set_account
7+
8+
def create
9+
account_action = Admin::AccountAction.new(resource_params)
10+
account_action.target_account = @account
11+
account_action.current_account = current_account
12+
account_action.save!
13+
14+
render_empty
15+
end
16+
17+
private
18+
19+
def set_account
20+
@account = Account.find(params[:account_id])
21+
end
22+
23+
def resource_params
24+
params.permit(
25+
:type,
26+
:report_id,
27+
:warning_preset_id,
28+
:text,
29+
:send_email_notification
30+
)
31+
end
32+
end
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::Admin::AccountsController < Api::BaseController
4+
include Authorization
5+
include AccountableConcern
6+
7+
LIMIT = 100
8+
9+
before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:accounts' }, only: [:index, :show]
10+
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }, except: [:index, :show]
11+
before_action :require_staff!
12+
before_action :set_accounts, only: :index
13+
before_action :set_account, except: :index
14+
before_action :require_local_account!, only: [:enable, :approve, :reject]
15+
16+
after_action :insert_pagination_headers, only: :index
17+
18+
FILTER_PARAMS = %i(
19+
local
20+
remote
21+
by_domain
22+
active
23+
pending
24+
disabled
25+
silenced
26+
suspended
27+
username
28+
display_name
29+
email
30+
ip
31+
staff
32+
).freeze
33+
34+
PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
35+
36+
def index
37+
authorize :account, :index?
38+
render json: @accounts, each_serializer: REST::Admin::AccountSerializer
39+
end
40+
41+
def show
42+
authorize @account, :show?
43+
render json: @account, serializer: REST::Admin::AccountSerializer
44+
end
45+
46+
def enable
47+
authorize @account.user, :enable?
48+
@account.user.enable!
49+
log_action :enable, @account.user
50+
render json: @account, serializer: REST::Admin::AccountSerializer
51+
end
52+
53+
def approve
54+
authorize @account.user, :approve?
55+
@account.user.approve!
56+
render json: @account, serializer: REST::Admin::AccountSerializer
57+
end
58+
59+
def reject
60+
authorize @account.user, :reject?
61+
SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
62+
render json: @account, serializer: REST::Admin::AccountSerializer
63+
end
64+
65+
def unsilence
66+
authorize @account, :unsilence?
67+
@account.unsilence!
68+
log_action :unsilence, @account
69+
render json: @account, serializer: REST::Admin::AccountSerializer
70+
end
71+
72+
def unsuspend
73+
authorize @account, :unsuspend?
74+
@account.unsuspend!
75+
log_action :unsuspend, @account
76+
render json: @account, serializer: REST::Admin::AccountSerializer
77+
end
78+
79+
private
80+
81+
def set_accounts
82+
@accounts = filtered_accounts.order(id: :desc).includes(user: [:invite_request, :invite]).paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
83+
end
84+
85+
def set_account
86+
@account = Account.find(params[:id])
87+
end
88+
89+
def filtered_accounts
90+
AccountFilter.new(filter_params).results
91+
end
92+
93+
def filter_params
94+
params.permit(*FILTER_PARAMS)
95+
end
96+
97+
def insert_pagination_headers
98+
set_pagination_headers(next_path, prev_path)
99+
end
100+
101+
def next_path
102+
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
103+
end
104+
105+
def prev_path
106+
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
107+
end
108+
109+
def pagination_max_id
110+
@accounts.last.id
111+
end
112+
113+
def pagination_since_id
114+
@accounts.first.id
115+
end
116+
117+
def records_continue?
118+
@accounts.size == limit_param(LIMIT)
119+
end
120+
121+
def pagination_params(core_params)
122+
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
123+
end
124+
125+
def require_local_account!
126+
forbidden unless @account.local? && @account.user.present?
127+
end
128+
end
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# frozen_string_literal: true
2+
3+
class Api::V1::Admin::ReportsController < Api::BaseController
4+
include Authorization
5+
include AccountableConcern
6+
7+
LIMIT = 100
8+
9+
before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:reports' }, only: [:index, :show]
10+
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:reports' }, except: [:index, :show]
11+
before_action :require_staff!
12+
before_action :set_reports, only: :index
13+
before_action :set_report, except: :index
14+
15+
after_action :insert_pagination_headers, only: :index
16+
17+
FILTER_PARAMS = %i(
18+
resolved
19+
account_id
20+
target_account_id
21+
).freeze
22+
23+
PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
24+
25+
def index
26+
authorize :report, :index?
27+
render json: @reports, each_serializer: REST::Admin::ReportSerializer
28+
end
29+
30+
def show
31+
authorize @report, :show?
32+
render json: @report, serializer: REST::Admin::ReportSerializer
33+
end
34+
35+
def assign_to_self
36+
authorize @report, :update?
37+
@report.update!(assigned_account_id: current_account.id)
38+
log_action :assigned_to_self, @report
39+
render json: @report, serializer: REST::Admin::ReportSerializer
40+
end
41+
42+
def unassign
43+
authorize @report, :update?
44+
@report.update!(assigned_account_id: nil)
45+
log_action :unassigned, @report
46+
render json: @report, serializer: REST::Admin::ReportSerializer
47+
end
48+
49+
def reopen
50+
authorize @report, :update?
51+
@report.unresolve!
52+
log_action :reopen, @report
53+
render json: @report, serializer: REST::Admin::ReportSerializer
54+
end
55+
56+
def resolve
57+
authorize @report, :update?
58+
@report.resolve!(current_account)
59+
log_action :resolve, @report
60+
render json: @report, serializer: REST::Admin::ReportSerializer
61+
end
62+
63+
private
64+
65+
def set_reports
66+
@reports = filtered_reports.order(id: :desc).with_accounts.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
67+
end
68+
69+
def set_report
70+
@report = Report.find(params[:id])
71+
end
72+
73+
def filtered_reports
74+
ReportFilter.new(filter_params).results
75+
end
76+
77+
def filter_params
78+
params.permit(*FILTER_PARAMS)
79+
end
80+
81+
def insert_pagination_headers
82+
set_pagination_headers(next_path, prev_path)
83+
end
84+
85+
def next_path
86+
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
87+
end
88+
89+
def prev_path
90+
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
91+
end
92+
93+
def pagination_max_id
94+
@reports.last.id
95+
end
96+
97+
def pagination_since_id
98+
@reports.first.id
99+
end
100+
101+
def records_continue?
102+
@reports.size == limit_param(LIMIT)
103+
end
104+
105+
def pagination_params(core_params)
106+
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
107+
end
108+
end

app/models/account.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ class Account < ApplicationRecord
107107
:confirmed?,
108108
:approved?,
109109
:pending?,
110+
:disabled?,
111+
:role,
110112
:admin?,
111113
:moderator?,
112114
:staff?,

app/models/account_filter.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ def scope_for(key, value)
3737
Account.without_suspended
3838
when 'pending'
3939
accounts_with_users.merge User.pending
40+
when 'disabled'
41+
accounts_with_users.merge User.disabled
4042
when 'silenced'
4143
Account.silenced
4244
when 'suspended'

app/models/concerns/user_roles.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ def staff?
1313
admin? || moderator?
1414
end
1515

16+
def role=(value)
17+
case value
18+
when 'admin'
19+
self.admin = true
20+
self.moderator = false
21+
when 'moderator'
22+
self.admin = false
23+
self.moderator = true
24+
else
25+
self.admin = false
26+
self.moderator = false
27+
end
28+
end
29+
1630
def role
1731
if admin?
1832
'admin'

app/models/report.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#
1818

1919
class Report < ApplicationRecord
20+
include Paginable
21+
2022
belongs_to :account
2123
belongs_to :target_account, class_name: 'Account'
2224
belongs_to :action_taken_by_account, class_name: 'Account', optional: true
@@ -26,6 +28,7 @@ class Report < ApplicationRecord
2628

2729
scope :unresolved, -> { where(action_taken: false) }
2830
scope :resolved, -> { where(action_taken: true) }
31+
scope :with_accounts, -> { includes([:account, :target_account, :action_taken_by_account, :assigned_account].each_with_object({}) { |k, h| h[k] = { user: [:invite_request, :invite] } }) }
2932

3033
validates :comment, length: { maximum: 1000 }
3134

app/models/report_filter.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ def initialize(params)
99

1010
def results
1111
scope = Report.unresolved
12+
1213
params.each do |key, value|
1314
scope = scope.merge scope_for(key, value)
1415
end
16+
1517
scope
1618
end
1719

app/models/user.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ class User < ApplicationRecord
8787
scope :approved, -> { where(approved: true) }
8888
scope :confirmed, -> { where.not(confirmed_at: nil) }
8989
scope :enabled, -> { where(disabled: false) }
90+
scope :disabled, -> { where(disabled: true) }
9091
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
9192
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) }
9293
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }

0 commit comments

Comments
 (0)