Skip to content

Commit

Permalink
Add moderation API (mastodon#9387)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron authored Jun 20, 2019
1 parent 2cb68b3 commit 2839d1d
Show file tree
Hide file tree
Showing 18 changed files with 735 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/controllers/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def filter_params
:by_domain,
:active,
:pending,
:disabled,
:silenced,
:suspended,
:username,
Expand Down
32 changes: 32 additions & 0 deletions app/controllers/api/v1/admin/account_actions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

class Api::V1::Admin::AccountActionsController < Api::BaseController
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }
before_action :require_staff!
before_action :set_account

def create
account_action = Admin::AccountAction.new(resource_params)
account_action.target_account = @account
account_action.current_account = current_account
account_action.save!

render_empty
end

private

def set_account
@account = Account.find(params[:account_id])
end

def resource_params
params.permit(
:type,
:report_id,
:warning_preset_id,
:text,
:send_email_notification
)
end
end
128 changes: 128 additions & 0 deletions app/controllers/api/v1/admin/accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# frozen_string_literal: true

class Api::V1::Admin::AccountsController < Api::BaseController
include Authorization
include AccountableConcern

LIMIT = 100

before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:accounts' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:accounts' }, except: [:index, :show]
before_action :require_staff!
before_action :set_accounts, only: :index
before_action :set_account, except: :index
before_action :require_local_account!, only: [:enable, :approve, :reject]

after_action :insert_pagination_headers, only: :index

FILTER_PARAMS = %i(
local
remote
by_domain
active
pending
disabled
silenced
suspended
username
display_name
email
ip
staff
).freeze

PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze

def index
authorize :account, :index?
render json: @accounts, each_serializer: REST::Admin::AccountSerializer
end

def show
authorize @account, :show?
render json: @account, serializer: REST::Admin::AccountSerializer
end

def enable
authorize @account.user, :enable?
@account.user.enable!
log_action :enable, @account.user
render json: @account, serializer: REST::Admin::AccountSerializer
end

def approve
authorize @account.user, :approve?
@account.user.approve!
render json: @account, serializer: REST::Admin::AccountSerializer
end

def reject
authorize @account.user, :reject?
SuspendAccountService.new.call(@account, including_user: true, destroy: true, skip_distribution: true)
render json: @account, serializer: REST::Admin::AccountSerializer
end

def unsilence
authorize @account, :unsilence?
@account.unsilence!
log_action :unsilence, @account
render json: @account, serializer: REST::Admin::AccountSerializer
end

def unsuspend
authorize @account, :unsuspend?
@account.unsuspend!
log_action :unsuspend, @account
render json: @account, serializer: REST::Admin::AccountSerializer
end

private

def set_accounts
@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))
end

def set_account
@account = Account.find(params[:id])
end

def filtered_accounts
AccountFilter.new(filter_params).results
end

def filter_params
params.permit(*FILTER_PARAMS)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
api_v1_admin_accounts_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end

def prev_path
api_v1_admin_accounts_url(pagination_params(min_id: pagination_since_id)) unless @accounts.empty?
end

def pagination_max_id
@accounts.last.id
end

def pagination_since_id
@accounts.first.id
end

def records_continue?
@accounts.size == limit_param(LIMIT)
end

def pagination_params(core_params)
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
end

def require_local_account!
forbidden unless @account.local? && @account.user.present?
end
end
108 changes: 108 additions & 0 deletions app/controllers/api/v1/admin/reports_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true

class Api::V1::Admin::ReportsController < Api::BaseController
include Authorization
include AccountableConcern

LIMIT = 100

before_action -> { doorkeeper_authorize! :'admin:read', :'admin:read:reports' }, only: [:index, :show]
before_action -> { doorkeeper_authorize! :'admin:write', :'admin:write:reports' }, except: [:index, :show]
before_action :require_staff!
before_action :set_reports, only: :index
before_action :set_report, except: :index

after_action :insert_pagination_headers, only: :index

FILTER_PARAMS = %i(
resolved
account_id
target_account_id
).freeze

PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze

def index
authorize :report, :index?
render json: @reports, each_serializer: REST::Admin::ReportSerializer
end

def show
authorize @report, :show?
render json: @report, serializer: REST::Admin::ReportSerializer
end

def assign_to_self
authorize @report, :update?
@report.update!(assigned_account_id: current_account.id)
log_action :assigned_to_self, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end

def unassign
authorize @report, :update?
@report.update!(assigned_account_id: nil)
log_action :unassigned, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end

def reopen
authorize @report, :update?
@report.unresolve!
log_action :reopen, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end

def resolve
authorize @report, :update?
@report.resolve!(current_account)
log_action :resolve, @report
render json: @report, serializer: REST::Admin::ReportSerializer
end

private

def set_reports
@reports = filtered_reports.order(id: :desc).with_accounts.paginate_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end

def set_report
@report = Report.find(params[:id])
end

def filtered_reports
ReportFilter.new(filter_params).results
end

def filter_params
params.permit(*FILTER_PARAMS)
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end

def next_path
api_v1_admin_reports_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end

def prev_path
api_v1_admin_reports_url(pagination_params(min_id: pagination_since_id)) unless @reports.empty?
end

def pagination_max_id
@reports.last.id
end

def pagination_since_id
@reports.first.id
end

def records_continue?
@reports.size == limit_param(LIMIT)
end

def pagination_params(core_params)
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
end
end
2 changes: 2 additions & 0 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class Account < ApplicationRecord
:confirmed?,
:approved?,
:pending?,
:disabled?,
:role,
:admin?,
:moderator?,
:staff?,
Expand Down
2 changes: 2 additions & 0 deletions app/models/account_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ def scope_for(key, value)
Account.without_suspended
when 'pending'
accounts_with_users.merge User.pending
when 'disabled'
accounts_with_users.merge User.disabled
when 'silenced'
Account.silenced
when 'suspended'
Expand Down
14 changes: 14 additions & 0 deletions app/models/concerns/user_roles.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,20 @@ def staff?
admin? || moderator?
end

def role=(value)
case value
when 'admin'
self.admin = true
self.moderator = false
when 'moderator'
self.admin = false
self.moderator = true
else
self.admin = false
self.moderator = false
end
end

def role
if admin?
'admin'
Expand Down
3 changes: 3 additions & 0 deletions app/models/report.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#

class Report < ApplicationRecord
include Paginable

belongs_to :account
belongs_to :target_account, class_name: 'Account'
belongs_to :action_taken_by_account, class_name: 'Account', optional: true
Expand All @@ -26,6 +28,7 @@ class Report < ApplicationRecord

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

validates :comment, length: { maximum: 1000 }

Expand Down
2 changes: 2 additions & 0 deletions app/models/report_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ def initialize(params)

def results
scope = Report.unresolved

params.each do |key, value|
scope = scope.merge scope_for(key, value)
end

scope
end

Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class User < ApplicationRecord
scope :approved, -> { where(approved: true) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
scope :enabled, -> { where(disabled: false) }
scope :disabled, -> { where(disabled: true) }
scope :inactive, -> { where(arel_table[:current_sign_in_at].lt(ACTIVE_DURATION.ago)) }
scope :active, -> { confirmed.where(arel_table[:current_sign_in_at].gteq(ACTIVE_DURATION.ago)).joins(:account).where(accounts: { suspended_at: nil }) }
scope :matches_email, ->(value) { where(arel_table[:email].matches("#{value}%")) }
Expand Down
Loading

0 comments on commit 2839d1d

Please sign in to comment.