@@ -127,6 +127,7 @@ module Admin
 | 
			
		||||
        :by_domain,
 | 
			
		||||
        :active,
 | 
			
		||||
        :pending,
 | 
			
		||||
        :disabled,
 | 
			
		||||
        :silenced,
 | 
			
		||||
        :suspended,
 | 
			
		||||
        :username,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										32
									
								
								app/controllers/api/v1/admin/account_actions_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								app/controllers/api/v1/admin/account_actions_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -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
									
								
								app/controllers/api/v1/admin/accounts_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								app/controllers/api/v1/admin/accounts_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -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
									
								
								app/controllers/api/v1/admin/reports_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								app/controllers/api/v1/admin/reports_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
@@ -106,6 +106,8 @@ class Account < ApplicationRecord
 | 
			
		||||
           :confirmed?,
 | 
			
		||||
           :approved?,
 | 
			
		||||
           :pending?,
 | 
			
		||||
           :disabled?,
 | 
			
		||||
           :role,
 | 
			
		||||
           :admin?,
 | 
			
		||||
           :moderator?,
 | 
			
		||||
           :staff?,
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,8 @@ class AccountFilter
 | 
			
		||||
      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'
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,20 @@ module UserRoles
 | 
			
		||||
    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'
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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 }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -9,9 +9,11 @@ class ReportFilter
 | 
			
		||||
 | 
			
		||||
  def results
 | 
			
		||||
    scope = Report.unresolved
 | 
			
		||||
 | 
			
		||||
    params.each do |key, value|
 | 
			
		||||
      scope = scope.merge scope_for(key, value)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    scope
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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}%")) }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								app/serializers/rest/admin/account_serializer.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								app/serializers/rest/admin/account_serializer.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class REST::Admin::AccountSerializer < ActiveModel::Serializer
 | 
			
		||||
  attributes :id, :username, :domain, :created_at,
 | 
			
		||||
             :email, :ip, :role, :confirmed, :suspended,
 | 
			
		||||
             :silenced, :disabled, :approved, :locale,
 | 
			
		||||
             :invite_request
 | 
			
		||||
 | 
			
		||||
  attribute :created_by_application_id, if: :created_by_application?
 | 
			
		||||
  attribute :invited_by_account_id, if: :invited?
 | 
			
		||||
 | 
			
		||||
  has_one :account, serializer: REST::AccountSerializer
 | 
			
		||||
 | 
			
		||||
  def id
 | 
			
		||||
    object.id.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def email
 | 
			
		||||
    object.user_email
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ip
 | 
			
		||||
    object.user_current_sign_in_ip.to_s.presence
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    object.user_role
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def suspended
 | 
			
		||||
    object.suspended?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def silenced
 | 
			
		||||
    object.silenced?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def confirmed
 | 
			
		||||
    object.user_confirmed?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disabled
 | 
			
		||||
    object.user_disabled?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def approved
 | 
			
		||||
    object.user_approved?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def account
 | 
			
		||||
    object
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def locale
 | 
			
		||||
    object.user_locale
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def created_by_application_id
 | 
			
		||||
    object.user&.created_by_application_id&.to_s&.presence
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invite_request
 | 
			
		||||
    object.user&.invite_request&.text
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invited_by_account_id
 | 
			
		||||
    object.user&.invite&.user&.account_id&.to_s&.presence
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invited?
 | 
			
		||||
    object.user&.invited?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def created_by_application?
 | 
			
		||||
    object.user&.created_by_application_id&.present?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										16
									
								
								app/serializers/rest/admin/report_serializer.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/serializers/rest/admin/report_serializer.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class REST::Admin::ReportSerializer < ActiveModel::Serializer
 | 
			
		||||
  attributes :id, :action_taken, :comment, :created_at, :updated_at
 | 
			
		||||
 | 
			
		||||
  has_one :account, serializer: REST::Admin::AccountSerializer
 | 
			
		||||
  has_one :target_account, serializer: REST::Admin::AccountSerializer
 | 
			
		||||
  has_one :assigned_account, serializer: REST::Admin::AccountSerializer
 | 
			
		||||
  has_one :action_taken_by_account, serializer: REST::Admin::AccountSerializer
 | 
			
		||||
 | 
			
		||||
  has_many :statuses, serializer: REST::StatusSerializer
 | 
			
		||||
 | 
			
		||||
  def id
 | 
			
		||||
    object.id.to_s
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -80,7 +80,13 @@ Doorkeeper.configure do
 | 
			
		||||
                  :'read:search',
 | 
			
		||||
                  :'read:statuses',
 | 
			
		||||
                  :follow,
 | 
			
		||||
                  :push
 | 
			
		||||
                  :push,
 | 
			
		||||
                  :'admin:read',
 | 
			
		||||
                  :'admin:read:accounts',
 | 
			
		||||
                  :'admin:read:reports',
 | 
			
		||||
                  :'admin:write',
 | 
			
		||||
                  :'admin:write:accounts',
 | 
			
		||||
                  :'admin:write:reports'
 | 
			
		||||
 | 
			
		||||
  # Change the way client credentials are retrieved from the request object.
 | 
			
		||||
  # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
 | 
			
		||||
 
 | 
			
		||||
@@ -114,6 +114,12 @@ en:
 | 
			
		||||
      application:
 | 
			
		||||
        title: OAuth authorization required
 | 
			
		||||
    scopes:
 | 
			
		||||
      admin:read: read all data on the server
 | 
			
		||||
      admin:read:accounts: read sensitive information of all accounts
 | 
			
		||||
      admin:read:reports: read sensitive information of all reports and reported accounts
 | 
			
		||||
      admin:write: modify all data on the server
 | 
			
		||||
      admin:write:accounts: perform moderation actions on accounts
 | 
			
		||||
      admin:write:reports: perform moderation actions on reports
 | 
			
		||||
      follow: modify account relationships
 | 
			
		||||
      push: receive your push notifications
 | 
			
		||||
      read: read all your account's data
 | 
			
		||||
 
 | 
			
		||||
@@ -398,6 +398,29 @@ Rails.application.routes.draw do
 | 
			
		||||
      namespace :push do
 | 
			
		||||
        resource :subscription, only: [:create, :show, :update, :destroy]
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      namespace :admin do
 | 
			
		||||
        resources :accounts, only: [:index, :show] do
 | 
			
		||||
          member do
 | 
			
		||||
            post :enable
 | 
			
		||||
            post :unsilence
 | 
			
		||||
            post :unsuspend
 | 
			
		||||
            post :approve
 | 
			
		||||
            post :reject
 | 
			
		||||
          end
 | 
			
		||||
 | 
			
		||||
          resource :action, only: [:create], controller: 'account_actions'
 | 
			
		||||
        end
 | 
			
		||||
 | 
			
		||||
        resources :reports, only: [:index, :show] do
 | 
			
		||||
          member do
 | 
			
		||||
            post :assign_to_self
 | 
			
		||||
            post :unassign
 | 
			
		||||
            post :reopen
 | 
			
		||||
            post :resolve
 | 
			
		||||
          end
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    namespace :v2 do
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Api::V1::Admin::AccountActionsController, type: :controller do
 | 
			
		||||
  render_views
 | 
			
		||||
 | 
			
		||||
  let(:role)   { 'moderator' }
 | 
			
		||||
  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
 | 
			
		||||
  let(:scopes) { 'admin:read admin:write' }
 | 
			
		||||
  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 | 
			
		||||
  let(:account) { Fabricate(:user).account }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    allow(controller).to receive(:doorkeeper_token) { token }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong scope' do |wrong_scope|
 | 
			
		||||
    let(:scopes) { wrong_scope }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong role' do |wrong_role|
 | 
			
		||||
    let(:role) { wrong_role }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #create' do
 | 
			
		||||
    before do
 | 
			
		||||
      post :create, params: { account_id: account.id, type: 'disable' }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'performs action against account' do
 | 
			
		||||
      expect(account.reload.user_disabled?).to be true
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'logs action' do
 | 
			
		||||
      log_item = Admin::ActionLog.last
 | 
			
		||||
 | 
			
		||||
      expect(log_item).to_not be_nil
 | 
			
		||||
      expect(log_item.action).to eq :disable
 | 
			
		||||
      expect(log_item.account_id).to eq user.account_id
 | 
			
		||||
      expect(log_item.target_id).to eq account.user.id
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										147
									
								
								spec/controllers/api/v1/admin/accounts_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								spec/controllers/api/v1/admin/accounts_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
 | 
			
		||||
  render_views
 | 
			
		||||
 | 
			
		||||
  let(:role)   { 'moderator' }
 | 
			
		||||
  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
 | 
			
		||||
  let(:scopes) { 'admin:read admin:write' }
 | 
			
		||||
  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 | 
			
		||||
  let(:account) { Fabricate(:user).account }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    allow(controller).to receive(:doorkeeper_token) { token }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong scope' do |wrong_scope|
 | 
			
		||||
    let(:scopes) { wrong_scope }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong role' do |wrong_role|
 | 
			
		||||
    let(:role) { wrong_role }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #index' do
 | 
			
		||||
    before do
 | 
			
		||||
      get :index
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #show' do
 | 
			
		||||
    before do
 | 
			
		||||
      get :show, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #approve' do
 | 
			
		||||
    before do
 | 
			
		||||
      account.user.update(approved: false)
 | 
			
		||||
      post :approve, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'approves user' do
 | 
			
		||||
      expect(account.reload.user_approved?).to be true
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #reject' do
 | 
			
		||||
    before do
 | 
			
		||||
      account.user.update(approved: false)
 | 
			
		||||
      post :reject, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'removes user' do
 | 
			
		||||
      expect(User.where(id: account.user.id).count).to eq 0
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #enable' do
 | 
			
		||||
    before do
 | 
			
		||||
      account.user.update(disabled: true)
 | 
			
		||||
      post :enable, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'enables user' do
 | 
			
		||||
      expect(account.reload.user_disabled?).to be false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #unsuspend' do
 | 
			
		||||
    before do
 | 
			
		||||
      account.touch(:suspended_at)
 | 
			
		||||
      post :unsuspend, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'unsuspends account' do
 | 
			
		||||
      expect(account.reload.suspended?).to be false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #unsilence' do
 | 
			
		||||
    before do
 | 
			
		||||
      account.touch(:silenced_at)
 | 
			
		||||
      post :unsilence, params: { id: account.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it 'unsilences account' do
 | 
			
		||||
      expect(account.reload.silenced?).to be false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										109
									
								
								spec/controllers/api/v1/admin/reports_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								spec/controllers/api/v1/admin/reports_controller_spec.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,109 @@
 | 
			
		||||
require 'rails_helper'
 | 
			
		||||
 | 
			
		||||
RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
 | 
			
		||||
  render_views
 | 
			
		||||
 | 
			
		||||
  let(:role)   { 'moderator' }
 | 
			
		||||
  let(:user)   { Fabricate(:user, role: role, account: Fabricate(:account, username: 'alice')) }
 | 
			
		||||
  let(:scopes) { 'admin:read admin:write' }
 | 
			
		||||
  let(:token)  { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
 | 
			
		||||
  let(:report) { Fabricate(:report) }
 | 
			
		||||
 | 
			
		||||
  before do
 | 
			
		||||
    allow(controller).to receive(:doorkeeper_token) { token }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong scope' do |wrong_scope|
 | 
			
		||||
    let(:scopes) { wrong_scope }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  shared_examples 'forbidden for wrong role' do |wrong_role|
 | 
			
		||||
    let(:role) { wrong_role }
 | 
			
		||||
 | 
			
		||||
    it 'returns http forbidden' do
 | 
			
		||||
      expect(response).to have_http_status(403)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #index' do
 | 
			
		||||
    before do
 | 
			
		||||
      get :index
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'GET #show' do
 | 
			
		||||
    before do
 | 
			
		||||
      get :show, params: { id: report.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #resolve' do
 | 
			
		||||
    before do
 | 
			
		||||
      post :resolve, params: { id: report.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #reopen' do
 | 
			
		||||
    before do
 | 
			
		||||
      post :reopen, params: { id: report.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #assign_to_self' do
 | 
			
		||||
    before do
 | 
			
		||||
      post :assign_to_self, params: { id: report.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  describe 'POST #unassign' do
 | 
			
		||||
    before do
 | 
			
		||||
      post :unassign, params: { id: report.id }
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    it_behaves_like 'forbidden for wrong scope', 'write:statuses'
 | 
			
		||||
    it_behaves_like 'forbidden for wrong role', 'user'
 | 
			
		||||
 | 
			
		||||
    it 'returns http success' do
 | 
			
		||||
      expect(response).to have_http_status(200)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user