Add moderator role and add pundit policies for admin actions (#5635)
* Add moderator role and add pundit policies for admin actions * Add rake task for turning user into mod and revoking it again * Fix handling of unauthorized exception * Deliver new report e-mails to staff, not just admins * Add promote/demote to admin UI, hide some actions conditionally * Fix unused i18n
This commit is contained in:
		@@ -1,31 +1,41 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::AccountModerationNotesController < Admin::BaseController
 | 
			
		||||
  def create
 | 
			
		||||
    @account_moderation_note = current_account.account_moderation_notes.new(resource_params)
 | 
			
		||||
    if @account_moderation_note.save
 | 
			
		||||
      @target_account = @account_moderation_note.target_account
 | 
			
		||||
      redirect_to admin_account_path(@target_account.id), notice: I18n.t('admin.account_moderation_notes.created_msg')
 | 
			
		||||
    else
 | 
			
		||||
      @account = @account_moderation_note.target_account
 | 
			
		||||
      @moderation_notes = @account.targeted_moderation_notes.latest
 | 
			
		||||
      render template: 'admin/accounts/show'
 | 
			
		||||
module Admin
 | 
			
		||||
  class AccountModerationNotesController < BaseController
 | 
			
		||||
    before_action :set_account_moderation_note, only: [:destroy]
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize AccountModerationNote, :create?
 | 
			
		||||
 | 
			
		||||
      @account_moderation_note = current_account.account_moderation_notes.new(resource_params)
 | 
			
		||||
 | 
			
		||||
      if @account_moderation_note.save
 | 
			
		||||
        redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.created_msg')
 | 
			
		||||
      else
 | 
			
		||||
        @account          = @account_moderation_note.target_account
 | 
			
		||||
        @moderation_notes = @account.targeted_moderation_notes.latest
 | 
			
		||||
 | 
			
		||||
        render template: 'admin/accounts/show'
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @account_moderation_note, :destroy?
 | 
			
		||||
      @account_moderation_note.destroy
 | 
			
		||||
      redirect_to admin_account_path(@account_moderation_note.target_account_id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg')
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def resource_params
 | 
			
		||||
      params.require(:account_moderation_note).permit(
 | 
			
		||||
        :content,
 | 
			
		||||
        :target_account_id
 | 
			
		||||
      )
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def set_account_moderation_note
 | 
			
		||||
      @account_moderation_note = AccountModerationNote.find(params[:id])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy
 | 
			
		||||
    @account_moderation_note = AccountModerationNote.find(params[:id])
 | 
			
		||||
    @target_account = @account_moderation_note.target_account
 | 
			
		||||
    @account_moderation_note.destroy
 | 
			
		||||
    redirect_to admin_account_path(@target_account.id), notice: I18n.t('admin.account_moderation_notes.destroyed_msg')
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def resource_params
 | 
			
		||||
    params.require(:account_moderation_note).permit(
 | 
			
		||||
      :content,
 | 
			
		||||
      :target_account_id
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -7,40 +7,49 @@ module Admin
 | 
			
		||||
    before_action :require_local_account!, only: [:enable, :disable, :memorialize]
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :account, :index?
 | 
			
		||||
      @accounts = filtered_accounts.page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def show
 | 
			
		||||
      authorize @account, :show?
 | 
			
		||||
      @account_moderation_note = current_account.account_moderation_notes.new(target_account: @account)
 | 
			
		||||
      @moderation_notes = @account.targeted_moderation_notes.latest
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def subscribe
 | 
			
		||||
      authorize @account, :subscribe?
 | 
			
		||||
      Pubsubhubbub::SubscribeWorker.perform_async(@account.id)
 | 
			
		||||
      redirect_to admin_account_path(@account.id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def unsubscribe
 | 
			
		||||
      authorize @account, :unsubscribe?
 | 
			
		||||
      Pubsubhubbub::UnsubscribeWorker.perform_async(@account.id)
 | 
			
		||||
      redirect_to admin_account_path(@account.id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def memorialize
 | 
			
		||||
      authorize @account, :memorialize?
 | 
			
		||||
      @account.memorialize!
 | 
			
		||||
      redirect_to admin_account_path(@account.id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def enable
 | 
			
		||||
      authorize @account.user, :enable?
 | 
			
		||||
      @account.user.enable!
 | 
			
		||||
      redirect_to admin_account_path(@account.id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def disable
 | 
			
		||||
      authorize @account.user, :disable?
 | 
			
		||||
      @account.user.disable!
 | 
			
		||||
      redirect_to admin_account_path(@account.id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def redownload
 | 
			
		||||
      authorize @account, :redownload?
 | 
			
		||||
 | 
			
		||||
      @account.reset_avatar!
 | 
			
		||||
      @account.reset_header!
 | 
			
		||||
      @account.save!
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class BaseController < ApplicationController
 | 
			
		||||
    before_action :require_admin!
 | 
			
		||||
    include Authorization
 | 
			
		||||
 | 
			
		||||
    before_action :require_staff!
 | 
			
		||||
 | 
			
		||||
    layout 'admin'
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,18 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class ConfirmationsController < BaseController
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      account_user.confirm
 | 
			
		||||
      authorize @user, :confirm?
 | 
			
		||||
      @user.confirm!
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def account_user
 | 
			
		||||
      Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
 | 
			
		||||
    def set_user
 | 
			
		||||
      @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,18 @@ module Admin
 | 
			
		||||
    before_action :set_custom_emoji, except: [:index, :new, :create]
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :custom_emoji, :index?
 | 
			
		||||
      @custom_emojis = filtered_custom_emojis.eager_load(:local_counterpart).page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def new
 | 
			
		||||
      authorize :custom_emoji, :create?
 | 
			
		||||
      @custom_emoji = CustomEmoji.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize :custom_emoji, :create?
 | 
			
		||||
 | 
			
		||||
      @custom_emoji = CustomEmoji.new(resource_params)
 | 
			
		||||
 | 
			
		||||
      if @custom_emoji.save
 | 
			
		||||
@@ -23,6 +27,8 @@ module Admin
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @custom_emoji, :update?
 | 
			
		||||
 | 
			
		||||
      if @custom_emoji.update(resource_params)
 | 
			
		||||
        redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.updated_msg')
 | 
			
		||||
      else
 | 
			
		||||
@@ -31,11 +37,14 @@ module Admin
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @custom_emoji, :destroy?
 | 
			
		||||
      @custom_emoji.destroy
 | 
			
		||||
      redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.destroyed_msg')
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def copy
 | 
			
		||||
      authorize @custom_emoji, :copy?
 | 
			
		||||
 | 
			
		||||
      emoji = CustomEmoji.find_or_create_by(domain: nil, shortcode: @custom_emoji.shortcode)
 | 
			
		||||
 | 
			
		||||
      if emoji.update(image: @custom_emoji.image)
 | 
			
		||||
@@ -48,11 +57,13 @@ module Admin
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def enable
 | 
			
		||||
      authorize @custom_emoji, :enable?
 | 
			
		||||
      @custom_emoji.update!(disabled: false)
 | 
			
		||||
      redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.enabled_msg')
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def disable
 | 
			
		||||
      authorize @custom_emoji, :disable?
 | 
			
		||||
      @custom_emoji.update!(disabled: true)
 | 
			
		||||
      redirect_to admin_custom_emojis_path, notice: I18n.t('admin.custom_emojis.disabled_msg')
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,18 @@ module Admin
 | 
			
		||||
    before_action :set_domain_block, only: [:show, :destroy]
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :domain_block, :index?
 | 
			
		||||
      @domain_blocks = DomainBlock.page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def new
 | 
			
		||||
      authorize :domain_block, :create?
 | 
			
		||||
      @domain_block = DomainBlock.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize :domain_block, :create?
 | 
			
		||||
 | 
			
		||||
      @domain_block = DomainBlock.new(resource_params)
 | 
			
		||||
 | 
			
		||||
      if @domain_block.save
 | 
			
		||||
@@ -23,9 +27,12 @@ module Admin
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def show; end
 | 
			
		||||
    def show
 | 
			
		||||
      authorize @domain_block, :show?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @domain_block, :destroy?
 | 
			
		||||
      UnblockDomainService.new.call(@domain_block, retroactive_unblock?)
 | 
			
		||||
      redirect_to admin_domain_blocks_path, notice: I18n.t('admin.domain_blocks.destroyed_msg')
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,18 @@ module Admin
 | 
			
		||||
    before_action :set_email_domain_block, only: [:show, :destroy]
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :email_domain_block, :index?
 | 
			
		||||
      @email_domain_blocks = EmailDomainBlock.page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def new
 | 
			
		||||
      authorize :email_domain_block, :create?
 | 
			
		||||
      @email_domain_block = EmailDomainBlock.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize :email_domain_block, :create?
 | 
			
		||||
 | 
			
		||||
      @email_domain_block = EmailDomainBlock.new(resource_params)
 | 
			
		||||
 | 
			
		||||
      if @email_domain_block.save
 | 
			
		||||
@@ -23,6 +27,7 @@ module Admin
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @email_domain_block, :destroy?
 | 
			
		||||
      @email_domain_block.destroy
 | 
			
		||||
      redirect_to admin_email_domain_blocks_path, notice: I18n.t('admin.email_domain_blocks.destroyed_msg')
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -3,10 +3,12 @@
 | 
			
		||||
module Admin
 | 
			
		||||
  class InstancesController < BaseController
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :instance, :index?
 | 
			
		||||
      @instances = ordered_instances
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def resubscribe
 | 
			
		||||
      authorize :instance, :resubscribe?
 | 
			
		||||
      params.require(:by_domain)
 | 
			
		||||
      Pubsubhubbub::SubscribeWorker.push_bulk(subscribeable_accounts.pluck(:id))
 | 
			
		||||
      redirect_to admin_instances_path
 | 
			
		||||
 
 | 
			
		||||
@@ -2,19 +2,20 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class ReportedStatusesController < BaseController
 | 
			
		||||
    include Authorization
 | 
			
		||||
 | 
			
		||||
    before_action :set_report
 | 
			
		||||
    before_action :set_status, only: [:update, :destroy]
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      @form = Form::StatusBatch.new(form_status_batch_params)
 | 
			
		||||
      flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save
 | 
			
		||||
      authorize :status, :update?
 | 
			
		||||
 | 
			
		||||
      @form         = Form::StatusBatch.new(form_status_batch_params)
 | 
			
		||||
      flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
 | 
			
		||||
 | 
			
		||||
      redirect_to admin_report_path(@report)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @status, :update?
 | 
			
		||||
      @status.update(status_params)
 | 
			
		||||
      redirect_to admin_report_path(@report)
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -5,14 +5,17 @@ module Admin
 | 
			
		||||
    before_action :set_report, except: [:index]
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :report, :index?
 | 
			
		||||
      @reports = filtered_reports.page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def show
 | 
			
		||||
      authorize @report, :show?
 | 
			
		||||
      @form = Form::StatusBatch.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @report, :update?
 | 
			
		||||
      process_report
 | 
			
		||||
      redirect_to admin_report_path(@report)
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -2,17 +2,18 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class ResetsController < BaseController
 | 
			
		||||
    before_action :set_account
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      @account.user.send_reset_password_instructions
 | 
			
		||||
      authorize @user, :reset_password?
 | 
			
		||||
      @user.send_reset_password_instructions
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def set_account
 | 
			
		||||
      @account = Account.find(params[:account_id])
 | 
			
		||||
    def set_user
 | 
			
		||||
      @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										25
									
								
								app/controllers/admin/roles_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/controllers/admin/roles_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class RolesController < BaseController
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
 | 
			
		||||
    def promote
 | 
			
		||||
      authorize @user, :promote?
 | 
			
		||||
      @user.promote!
 | 
			
		||||
      redirect_to admin_account_path(@user.account_id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def demote
 | 
			
		||||
      authorize @user, :demote?
 | 
			
		||||
      @user.demote!
 | 
			
		||||
      redirect_to admin_account_path(@user.account_id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def set_user
 | 
			
		||||
      @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -28,10 +28,13 @@ module Admin
 | 
			
		||||
    ).freeze
 | 
			
		||||
 | 
			
		||||
    def edit
 | 
			
		||||
      authorize :settings, :show?
 | 
			
		||||
      @admin_settings = Form::AdminSettings.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize :settings, :update?
 | 
			
		||||
 | 
			
		||||
      settings_params.each do |key, value|
 | 
			
		||||
        if UPLOAD_SETTINGS.include?(key)
 | 
			
		||||
          upload = SiteUpload.where(var: key).first_or_initialize(var: key)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,13 @@ module Admin
 | 
			
		||||
    before_action :set_account
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize @account, :silence?
 | 
			
		||||
      @account.update(silenced: true)
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @account, :unsilence?
 | 
			
		||||
      @account.update(silenced: false)
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,6 @@
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class StatusesController < BaseController
 | 
			
		||||
    include Authorization
 | 
			
		||||
 | 
			
		||||
    helper_method :current_params
 | 
			
		||||
 | 
			
		||||
    before_action :set_account
 | 
			
		||||
@@ -12,24 +10,30 @@ module Admin
 | 
			
		||||
    PER_PAGE = 20
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :status, :index?
 | 
			
		||||
 | 
			
		||||
      @statuses = @account.statuses
 | 
			
		||||
 | 
			
		||||
      if params[:media]
 | 
			
		||||
        account_media_status_ids = @account.media_attachments.attached.reorder(nil).select(:status_id).distinct
 | 
			
		||||
        @statuses.merge!(Status.where(id: account_media_status_ids))
 | 
			
		||||
      end
 | 
			
		||||
      @statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE)
 | 
			
		||||
 | 
			
		||||
      @form = Form::StatusBatch.new
 | 
			
		||||
      @statuses = @statuses.preload(:media_attachments, :mentions).page(params[:page]).per(PER_PAGE)
 | 
			
		||||
      @form     = Form::StatusBatch.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      @form = Form::StatusBatch.new(form_status_batch_params)
 | 
			
		||||
      flash[:alert] = t('admin.statuses.failed_to_execute') unless @form.save
 | 
			
		||||
      authorize :status, :update?
 | 
			
		||||
 | 
			
		||||
      @form         = Form::StatusBatch.new(form_status_batch_params)
 | 
			
		||||
      flash[:alert] = I18n.t('admin.statuses.failed_to_execute') unless @form.save
 | 
			
		||||
 | 
			
		||||
      redirect_to admin_account_statuses_path(@account.id, current_params)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @status, :update?
 | 
			
		||||
      @status.update(status_params)
 | 
			
		||||
      redirect_to admin_account_statuses_path(@account.id, current_params)
 | 
			
		||||
    end
 | 
			
		||||
@@ -60,6 +64,7 @@ module Admin
 | 
			
		||||
 | 
			
		||||
    def current_params
 | 
			
		||||
      page = (params[:page] || 1).to_i
 | 
			
		||||
 | 
			
		||||
      {
 | 
			
		||||
        media: params[:media],
 | 
			
		||||
        page: page > 1 && page,
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
module Admin
 | 
			
		||||
  class SubscriptionsController < BaseController
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :subscription, :index?
 | 
			
		||||
      @subscriptions = ordered_subscriptions.page(requested_page)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,11 +5,13 @@ module Admin
 | 
			
		||||
    before_action :set_account
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize @account, :suspend?
 | 
			
		||||
      Admin::SuspensionWorker.perform_async(@account.id)
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @account, :unsuspend?
 | 
			
		||||
      @account.unsuspend!
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@ module Admin
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @user, :disable_2fa?
 | 
			
		||||
      @user.disable_two_factor!
 | 
			
		||||
      redirect_to admin_accounts_path
 | 
			
		||||
    end
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,7 @@ class Api::V1::ReportsController < Api::BaseController
 | 
			
		||||
      comment: report_params[:comment]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    User.admins.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
 | 
			
		||||
    User.staff.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later }
 | 
			
		||||
 | 
			
		||||
    render json: @report, serializer: REST::ReportSerializer
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ class ApplicationController < ActionController::Base
 | 
			
		||||
  rescue_from ActionController::RoutingError, with: :not_found
 | 
			
		||||
  rescue_from ActiveRecord::RecordNotFound, with: :not_found
 | 
			
		||||
  rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity
 | 
			
		||||
  rescue_from Mastodon::NotPermittedError, with: :forbidden
 | 
			
		||||
 | 
			
		||||
  before_action :store_current_location, except: :raise_not_found, unless: :devise_controller?
 | 
			
		||||
  before_action :check_suspension, if: :user_signed_in?
 | 
			
		||||
@@ -40,6 +41,10 @@ class ApplicationController < ActionController::Base
 | 
			
		||||
    redirect_to root_path unless current_user&.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_staff!
 | 
			
		||||
    redirect_to root_path unless current_user&.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def check_suspension
 | 
			
		||||
    forbidden if current_user.account.suspended?
 | 
			
		||||
  end
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
 | 
			
		||||
module Authorization
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
  include Pundit
 | 
			
		||||
 | 
			
		||||
  def pundit_user
 | 
			
		||||
 
 | 
			
		||||
@@ -35,6 +35,11 @@ module ApplicationHelper
 | 
			
		||||
    Rails.env.production? ? site_title : "#{site_title} (Dev)"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def can?(action, record)
 | 
			
		||||
    return false if record.nil?
 | 
			
		||||
    policy(record).public_send("#{action}?")
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def fa_icon(icon, attributes = {})
 | 
			
		||||
    class_names = attributes[:class]&.split(' ') || []
 | 
			
		||||
    class_names << 'fa'
 | 
			
		||||
 
 | 
			
		||||
@@ -32,6 +32,7 @@
 | 
			
		||||
#  filtered_languages        :string           default([]), not null, is an Array
 | 
			
		||||
#  account_id                :integer          not null
 | 
			
		||||
#  disabled                  :boolean          default(FALSE), not null
 | 
			
		||||
#  moderator                 :boolean          default(FALSE), not null
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class User < ApplicationRecord
 | 
			
		||||
@@ -53,8 +54,10 @@ class User < ApplicationRecord
 | 
			
		||||
  validates :locale, inclusion: I18n.available_locales.map(&:to_s), if: :locale?
 | 
			
		||||
  validates_with BlacklistedEmailValidator, if: :email_changed?
 | 
			
		||||
 | 
			
		||||
  scope :recent,    -> { order(id: :desc) }
 | 
			
		||||
  scope :admins,    -> { where(admin: true) }
 | 
			
		||||
  scope :recent, -> { order(id: :desc) }
 | 
			
		||||
  scope :admins, -> { where(admin: true) }
 | 
			
		||||
  scope :moderators, -> { where(moderator: true) }
 | 
			
		||||
  scope :staff, -> { admins.or(moderators) }
 | 
			
		||||
  scope :confirmed, -> { where.not(confirmed_at: nil) }
 | 
			
		||||
  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: false }) }
 | 
			
		||||
@@ -74,6 +77,20 @@ class User < ApplicationRecord
 | 
			
		||||
    confirmed_at.present?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def staff?
 | 
			
		||||
    admin? || moderator?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    if admin?
 | 
			
		||||
      'admin'
 | 
			
		||||
    elsif moderator?
 | 
			
		||||
      'moderator'
 | 
			
		||||
    else
 | 
			
		||||
      'user'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable!
 | 
			
		||||
    update!(disabled: true,
 | 
			
		||||
            last_sign_in_at: current_sign_in_at,
 | 
			
		||||
@@ -84,6 +101,27 @@ class User < ApplicationRecord
 | 
			
		||||
    update!(disabled: false)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def confirm!
 | 
			
		||||
    skip_confirmation!
 | 
			
		||||
    save!
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def promote!
 | 
			
		||||
    if moderator?
 | 
			
		||||
      update!(moderator: false, admin: true)
 | 
			
		||||
    elsif !admin?
 | 
			
		||||
      update!(moderator: true)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def demote!
 | 
			
		||||
    if admin?
 | 
			
		||||
      update!(admin: false, moderator: true)
 | 
			
		||||
    elsif moderator?
 | 
			
		||||
      update!(moderator: false)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable_two_factor!
 | 
			
		||||
    self.otp_required_for_login = false
 | 
			
		||||
    otp_backup_codes&.clear
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								app/policies/account_moderation_note_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/policies/account_moderation_note_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AccountModerationNotePolicy < ApplicationPolicy
 | 
			
		||||
  def create?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin? || owner?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def owner?
 | 
			
		||||
    record.account_id == current_account&.id
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										43
									
								
								app/policies/account_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								app/policies/account_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AccountPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def suspend?
 | 
			
		||||
    staff? && !record.user&.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsuspend?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def silence?
 | 
			
		||||
    staff? && !record.user&.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsilence?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redownload?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def subscribe?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsubscribe?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def memorialize?
 | 
			
		||||
    admin? && !record.user&.admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										18
									
								
								app/policies/application_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/policies/application_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class ApplicationPolicy
 | 
			
		||||
  attr_reader :current_account, :record
 | 
			
		||||
 | 
			
		||||
  def initialize(current_account, record)
 | 
			
		||||
    @current_account = current_account
 | 
			
		||||
    @record          = record
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  delegate :admin?, :moderator?, :staff?, to: :current_user, allow_nil: true
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def current_user
 | 
			
		||||
    current_account&.user
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										31
									
								
								app/policies/custom_emoji_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/policies/custom_emoji_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class CustomEmojiPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def copy?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										19
									
								
								app/policies/domain_block_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/policies/domain_block_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class DomainBlockPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										15
									
								
								app/policies/email_domain_block_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/policies/email_domain_block_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class EmailDomainBlockPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								app/policies/instance_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/policies/instance_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class InstancePolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def resubscribe?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										15
									
								
								app/policies/report_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								app/policies/report_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class ReportPolicy < ApplicationPolicy
 | 
			
		||||
  def update?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										11
									
								
								app/policies/settings_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								app/policies/settings_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class SettingsPolicy < ApplicationPolicy
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -1,20 +1,17 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class StatusPolicy
 | 
			
		||||
  attr_reader :account, :status
 | 
			
		||||
 | 
			
		||||
  def initialize(account, status)
 | 
			
		||||
    @account = account
 | 
			
		||||
    @status = status
 | 
			
		||||
class StatusPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    if direct?
 | 
			
		||||
      owned? || status.mentions.where(account: account).exists?
 | 
			
		||||
      owned? || record.mentions.where(account: current_account).exists?
 | 
			
		||||
    elsif private?
 | 
			
		||||
      owned? || account&.following?(status.account) || status.mentions.where(account: account).exists?
 | 
			
		||||
      owned? || current_account&.following?(author) || record.mentions.where(account: current_account).exists?
 | 
			
		||||
    else
 | 
			
		||||
      account.nil? || !status.account.blocking?(account)
 | 
			
		||||
      current_account.nil? || !author.blocking?(current_account)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
@@ -23,26 +20,30 @@ class StatusPolicy
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin? || owned?
 | 
			
		||||
    staff? || owned?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  alias unreblog? destroy?
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def admin?
 | 
			
		||||
    account&.user&.admin?
 | 
			
		||||
  def update?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def direct?
 | 
			
		||||
    status.direct_visibility?
 | 
			
		||||
    record.direct_visibility?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def owned?
 | 
			
		||||
    status.account.id == account&.id
 | 
			
		||||
    author.id == current_account&.id
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def private?
 | 
			
		||||
    status.private_visibility?
 | 
			
		||||
    record.private_visibility?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def author
 | 
			
		||||
    record.account
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										7
									
								
								app/policies/subscription_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/policies/subscription_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class SubscriptionPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										41
									
								
								app/policies/user_policy.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								app/policies/user_policy.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,41 @@
 | 
			
		||||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class UserPolicy < ApplicationPolicy
 | 
			
		||||
  def reset_password?
 | 
			
		||||
    staff? && !record.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable_2fa?
 | 
			
		||||
    admin? && !record.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def confirm?
 | 
			
		||||
    staff? && !record.confirmed?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable?
 | 
			
		||||
    admin? && !record.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def promote?
 | 
			
		||||
    admin? && promoteable?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def demote?
 | 
			
		||||
    admin? && !record.admin? && demoteable?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def promoteable?
 | 
			
		||||
    !record.staff? || !record.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def demoteable?
 | 
			
		||||
    record.staff?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -7,4 +7,4 @@
 | 
			
		||||
    %time.formatted{ datetime: account_moderation_note.created_at.iso8601, title: l(account_moderation_note.created_at) }
 | 
			
		||||
      = l account_moderation_note.created_at
 | 
			
		||||
  %td
 | 
			
		||||
    = link_to t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete
 | 
			
		||||
    = link_to t('admin.account_moderation_notes.delete'), admin_account_moderation_note_path(account_moderation_note), method: :delete if can?(:destroy, account_moderation_note)
 | 
			
		||||
 
 | 
			
		||||
@@ -17,16 +17,20 @@
 | 
			
		||||
      - if @account.local?
 | 
			
		||||
        %tr
 | 
			
		||||
          %th= t('admin.accounts.email')
 | 
			
		||||
          %td= @account.user_email
 | 
			
		||||
          %td
 | 
			
		||||
            = @account.user_email
 | 
			
		||||
 | 
			
		||||
            - if @account.user_confirmed?
 | 
			
		||||
              = fa_icon('check')
 | 
			
		||||
        %tr
 | 
			
		||||
          %th= t('admin.accounts.login_status')
 | 
			
		||||
          %td
 | 
			
		||||
            - if @account.user&.disabled?
 | 
			
		||||
              = t('admin.accounts.disabled')
 | 
			
		||||
              = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post
 | 
			
		||||
              = table_link_to 'unlock', t('admin.accounts.enable'), enable_admin_account_path(@account.id), method: :post if can?(:enable, @account.user)
 | 
			
		||||
            - else
 | 
			
		||||
              = t('admin.accounts.enabled')
 | 
			
		||||
              = table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post
 | 
			
		||||
              = table_link_to 'lock', t('admin.accounts.disable'), disable_admin_account_path(@account.id), method: :post if can?(:disable, @account.user)
 | 
			
		||||
        %tr
 | 
			
		||||
          %th= t('admin.accounts.most_recent_ip')
 | 
			
		||||
          %td= @account.user_current_sign_in_ip
 | 
			
		||||
@@ -71,28 +75,28 @@
 | 
			
		||||
%div{ style: 'overflow: hidden' }
 | 
			
		||||
  %div{ style: 'float: right' }
 | 
			
		||||
    - if @account.local?
 | 
			
		||||
      = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.reset_password'), admin_account_reset_path(@account.id), method: :create, class: 'button' if can?(:reset_password, @account.user)
 | 
			
		||||
      - if @account.user&.otp_required_for_login?
 | 
			
		||||
        = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button'
 | 
			
		||||
        = link_to t('admin.accounts.disable_two_factor_authentication'), admin_user_two_factor_authentication_path(@account.user.id), method: :delete, class: 'button' if can?(:disable_2fa, @account.user)
 | 
			
		||||
      - unless @account.memorial?
 | 
			
		||||
        = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button'
 | 
			
		||||
        = link_to t('admin.accounts.memorialize'), memorialize_admin_account_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:memorialize, @account)
 | 
			
		||||
    - else
 | 
			
		||||
      = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.redownload'), redownload_admin_account_path(@account.id), method: :post, class: 'button' if can?(:redownload, @account)
 | 
			
		||||
 | 
			
		||||
  %div{ style: 'float: left' }
 | 
			
		||||
    - if @account.silenced?
 | 
			
		||||
      = link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.undo_silenced'), admin_account_silence_path(@account.id), method: :delete, class: 'button' if can?(:unsilence, @account)
 | 
			
		||||
    - else
 | 
			
		||||
      = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.silence'), admin_account_silence_path(@account.id), method: :post, class: 'button' if can?(:silence, @account)
 | 
			
		||||
 | 
			
		||||
    - if @account.local?
 | 
			
		||||
      - unless @account.user_confirmed?
 | 
			
		||||
        = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button'
 | 
			
		||||
        = link_to t('admin.accounts.confirm'), admin_account_confirmation_path(@account.id), method: :post, class: 'button' if can?(:confirm, @account.user)
 | 
			
		||||
 | 
			
		||||
    - if @account.suspended?
 | 
			
		||||
      = link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.undo_suspension'), admin_account_suspension_path(@account.id), method: :delete, class: 'button' if can?(:unsuspend, @account)
 | 
			
		||||
    - else
 | 
			
		||||
      = link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button'
 | 
			
		||||
      = link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account)
 | 
			
		||||
 | 
			
		||||
- unless @account.local?
 | 
			
		||||
  %hr
 | 
			
		||||
@@ -118,9 +122,9 @@
 | 
			
		||||
 | 
			
		||||
  %div{ style: 'overflow: hidden' }
 | 
			
		||||
    %div{ style: 'float: right' }
 | 
			
		||||
      = link_to @account.subscribed? ? t('admin.accounts.resubscribe') : t('admin.accounts.subscribe'), subscribe_admin_account_path(@account.id), method: :post, class: 'button'
 | 
			
		||||
      = link_to @account.subscribed? ? t('admin.accounts.resubscribe') : t('admin.accounts.subscribe'), subscribe_admin_account_path(@account.id), method: :post, class: 'button' if can?(:subscribe, @account)
 | 
			
		||||
      - if @account.subscribed?
 | 
			
		||||
        = link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative'
 | 
			
		||||
        = link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account)
 | 
			
		||||
 | 
			
		||||
  %hr
 | 
			
		||||
  %h3 ActivityPub
 | 
			
		||||
@@ -141,6 +145,20 @@
 | 
			
		||||
          %th= t('admin.accounts.followers_url')
 | 
			
		||||
          %td= link_to @account.followers_url, @account.followers_url
 | 
			
		||||
 | 
			
		||||
- else
 | 
			
		||||
  %hr
 | 
			
		||||
 | 
			
		||||
  .table-wrapper
 | 
			
		||||
    %table.table
 | 
			
		||||
      %tbody
 | 
			
		||||
        %tr
 | 
			
		||||
          %th= t('admin.accounts.role')
 | 
			
		||||
          %td
 | 
			
		||||
            = t("admin.accounts.roles.#{@account.user&.role}")
 | 
			
		||||
          %td<
 | 
			
		||||
            = table_link_to 'angle-double-up', t('admin.accounts.promote'), promote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:promote, @account.user)
 | 
			
		||||
            = table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)
 | 
			
		||||
 | 
			
		||||
%hr
 | 
			
		||||
%h3= t('admin.accounts.moderation_notes')
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@ ignore_missing:
 | 
			
		||||
  - 'terms.body_html'
 | 
			
		||||
  - 'application_mailer.salutation'
 | 
			
		||||
  - 'errors.500'
 | 
			
		||||
 | 
			
		||||
ignore_unused:
 | 
			
		||||
  - 'activemodel.errors.*'
 | 
			
		||||
  - 'activerecord.attributes.*'
 | 
			
		||||
@@ -58,3 +59,4 @@ ignore_unused:
 | 
			
		||||
  - 'errors.messages.*'
 | 
			
		||||
  - 'activerecord.errors.models.doorkeeper/*'
 | 
			
		||||
  - 'errors.429'
 | 
			
		||||
  - 'admin.accounts.roles.*'
 | 
			
		||||
 
 | 
			
		||||
@@ -62,6 +62,7 @@ en:
 | 
			
		||||
      by_domain: Domain
 | 
			
		||||
      confirm: Confirm
 | 
			
		||||
      confirmed: Confirmed
 | 
			
		||||
      demote: Demote
 | 
			
		||||
      disable: Disable
 | 
			
		||||
      disable_two_factor_authentication: Disable 2FA
 | 
			
		||||
      disabled: Disabled
 | 
			
		||||
@@ -101,6 +102,7 @@ en:
 | 
			
		||||
      outbox_url: Outbox URL
 | 
			
		||||
      perform_full_suspension: Perform full suspension
 | 
			
		||||
      profile_url: Profile URL
 | 
			
		||||
      promote: Promote
 | 
			
		||||
      protocol: Protocol
 | 
			
		||||
      public: Public
 | 
			
		||||
      push_subscription_expires: PuSH subscription expires
 | 
			
		||||
@@ -108,6 +110,11 @@ en:
 | 
			
		||||
      reset: Reset
 | 
			
		||||
      reset_password: Reset password
 | 
			
		||||
      resubscribe: Resubscribe
 | 
			
		||||
      role: Permissions
 | 
			
		||||
      roles:
 | 
			
		||||
        admin: Administrator
 | 
			
		||||
        moderator: Moderator
 | 
			
		||||
        user: User
 | 
			
		||||
      salmon_url: Salmon URL
 | 
			
		||||
      search: Search
 | 
			
		||||
      shared_inbox_url: Shared Inbox URL
 | 
			
		||||
 
 | 
			
		||||
@@ -20,16 +20,16 @@ SimpleNavigation::Configuration.run do |navigation|
 | 
			
		||||
      development.item :your_apps, safe_join([fa_icon('list fw'), t('settings.your_apps')]), settings_applications_url, highlights_on: %r{/settings/applications}
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.admin? } do |admin|
 | 
			
		||||
    primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin|
 | 
			
		||||
      admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports}
 | 
			
		||||
      admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts}
 | 
			
		||||
      admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}
 | 
			
		||||
      admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url
 | 
			
		||||
      admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}
 | 
			
		||||
      admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}
 | 
			
		||||
      admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }
 | 
			
		||||
      admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }
 | 
			
		||||
      admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url
 | 
			
		||||
      admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url, highlights_on: %r{/admin/instances}, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :domain_blocks, safe_join([fa_icon('lock fw'), t('admin.domain_blocks.title')]), admin_domain_blocks_url, highlights_on: %r{/admin/domain_blocks}, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }
 | 
			
		||||
      admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -137,6 +137,13 @@ Rails.application.routes.draw do
 | 
			
		||||
      resource :suspension, only: [:create, :destroy]
 | 
			
		||||
      resource :confirmation, only: [:create]
 | 
			
		||||
      resources :statuses, only: [:index, :create, :update, :destroy]
 | 
			
		||||
 | 
			
		||||
      resource :role do
 | 
			
		||||
        member do
 | 
			
		||||
          post :promote
 | 
			
		||||
          post :demote
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    resources :users, only: [] do
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										15
									
								
								db/migrate/20171109012327_add_moderator_to_accounts.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								db/migrate/20171109012327_add_moderator_to_accounts.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
require Rails.root.join('lib', 'mastodon', 'migration_helpers')
 | 
			
		||||
 | 
			
		||||
class AddModeratorToAccounts < ActiveRecord::Migration[5.1]
 | 
			
		||||
  include Mastodon::MigrationHelpers
 | 
			
		||||
 | 
			
		||||
  disable_ddl_transaction!
 | 
			
		||||
 | 
			
		||||
  def up
 | 
			
		||||
    safety_assured { add_column_with_default :users, :moderator, :bool, default: false }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def down
 | 
			
		||||
    remove_column :users, :moderator
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
#
 | 
			
		||||
# It's strongly recommended that you check this file into your version control system.
 | 
			
		||||
 | 
			
		||||
ActiveRecord::Schema.define(version: 20171107143624) do
 | 
			
		||||
ActiveRecord::Schema.define(version: 20171109012327) do
 | 
			
		||||
 | 
			
		||||
  # These are extensions that must be enabled in order to support this database
 | 
			
		||||
  enable_extension "plpgsql"
 | 
			
		||||
@@ -437,6 +437,7 @@ ActiveRecord::Schema.define(version: 20171107143624) do
 | 
			
		||||
    t.string "filtered_languages", default: [], null: false, array: true
 | 
			
		||||
    t.bigint "account_id", null: false
 | 
			
		||||
    t.boolean "disabled", default: false, null: false
 | 
			
		||||
    t.boolean "moderator", default: false, null: false
 | 
			
		||||
    t.index ["account_id"], name: "index_users_on_account_id"
 | 
			
		||||
    t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
 | 
			
		||||
    t.index ["email"], name: "index_users_on_email", unique: true
 | 
			
		||||
 
 | 
			
		||||
@@ -10,14 +10,41 @@ namespace :mastodon do
 | 
			
		||||
  desc 'Turn a user into an admin, identified by the USERNAME environment variable'
 | 
			
		||||
  task make_admin: :environment do
 | 
			
		||||
    include RoutingHelper
 | 
			
		||||
 | 
			
		||||
    account_username = ENV.fetch('USERNAME')
 | 
			
		||||
    user = User.joins(:account).where(accounts: { username: account_username })
 | 
			
		||||
    user             = User.joins(:account).where(accounts: { username: account_username })
 | 
			
		||||
 | 
			
		||||
    if user.present?
 | 
			
		||||
      user.update(admin: true)
 | 
			
		||||
      puts "Congrats! #{account_username} is now an admin. \\o/\nNavigate to #{edit_admin_settings_url} to get started"
 | 
			
		||||
    else
 | 
			
		||||
      puts "User could not be found; please make sure an Account with the `#{account_username}` username exists."
 | 
			
		||||
      puts "User could not be found; please make sure an account with the `#{account_username}` username exists."
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  desc 'Turn a user into a moderator, identified by the USERNAME environment variable'
 | 
			
		||||
  task make_mod: :environment do
 | 
			
		||||
    account_username = ENV.fetch('USERNAME')
 | 
			
		||||
    user             = User.joins(:account).where(accounts: { username: account_username })
 | 
			
		||||
 | 
			
		||||
    if user.present?
 | 
			
		||||
      user.update(moderator: true)
 | 
			
		||||
      puts "Congrats! #{account_username} is now a moderator \\o/"
 | 
			
		||||
    else
 | 
			
		||||
      puts "User could not be found; please make sure an account with the `#{account_username}` username exists."
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  desc 'Remove admin and moderator privileges from user identified by the USERNAME environment variable'
 | 
			
		||||
  task revoke_staff: :environment do
 | 
			
		||||
    account_username = ENV.fetch('USERNAME')
 | 
			
		||||
    user             = User.joins(:account).where(accounts: { username: account_username })
 | 
			
		||||
 | 
			
		||||
    if user.present?
 | 
			
		||||
      user.update(moderator: false, admin: false)
 | 
			
		||||
      puts "#{account_username} is no longer admin or moderator."
 | 
			
		||||
    else
 | 
			
		||||
      puts "User could not be found; please make sure an account with the `#{account_username}` username exists."
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user