Add customizable user roles (#18641)
* Add customizable user roles * Various fixes and improvements * Add migration for old settings and fix tootctl role management
This commit is contained in:
		
							parent
							
								
									1b4054256f
								
							
						
					
					
						commit
						44b2ee3485
					
				
					 187 changed files with 1945 additions and 1032 deletions
				
			
		| 
						 | 
				
			
			@ -67,7 +67,7 @@ Lint/UselessAccessModifier:
 | 
			
		|||
    - class_methods
 | 
			
		||||
 | 
			
		||||
Metrics/AbcSize:
 | 
			
		||||
  Max: 100
 | 
			
		||||
  Max: 115
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'lib/mastodon/*_cli.rb'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ Metrics/BlockNesting:
 | 
			
		|||
 | 
			
		||||
Metrics/ClassLength:
 | 
			
		||||
  CountComments: false
 | 
			
		||||
  Max: 400
 | 
			
		||||
  Max: 500
 | 
			
		||||
  Exclude:
 | 
			
		||||
    - 'lib/mastodon/*_cli.rb'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,11 +5,15 @@ module Admin
 | 
			
		|||
    before_action :set_account
 | 
			
		||||
 | 
			
		||||
    def new
 | 
			
		||||
      authorize @account, :show?
 | 
			
		||||
 | 
			
		||||
      @account_action  = Admin::AccountAction.new(type: params[:type], report_id: params[:report_id], send_email_notification: true, include_statuses: true)
 | 
			
		||||
      @warning_presets = AccountWarningPreset.all
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize @account, :show?
 | 
			
		||||
 | 
			
		||||
      account_action                 = Admin::AccountAction.new(resource_params)
 | 
			
		||||
      account_action.target_account  = @account
 | 
			
		||||
      account_action.current_account = current_account
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def batch
 | 
			
		||||
      authorize :account, :index?
 | 
			
		||||
 | 
			
		||||
      @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
      @form.save
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,10 @@ module Admin
 | 
			
		|||
  class ActionLogsController < BaseController
 | 
			
		||||
    before_action :set_action_logs
 | 
			
		||||
 | 
			
		||||
    def index; end
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :audit_log, :index?
 | 
			
		||||
      @auditable_accounts = Account.where(id: Admin::ActionLog.reorder(nil).select('distinct account_id')).select(:id, :username)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,8 +7,8 @@ module Admin
 | 
			
		|||
 | 
			
		||||
    layout 'admin'
 | 
			
		||||
 | 
			
		||||
    before_action :require_staff!
 | 
			
		||||
    before_action :set_body_classes
 | 
			
		||||
    after_action :verify_authorized
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def batch
 | 
			
		||||
      authorize :custom_emoji, :index?
 | 
			
		||||
 | 
			
		||||
      @form = Form::CustomEmojiBatch.new(form_custom_emoji_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
      @form.save
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,7 +5,9 @@ module Admin
 | 
			
		|||
    include Redisable
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      @system_checks         = Admin::SystemCheck.perform
 | 
			
		||||
      authorize :dashboard, :index?
 | 
			
		||||
 | 
			
		||||
      @system_checks         = Admin::SystemCheck.perform(current_user)
 | 
			
		||||
      @time_period           = (29.days.ago.to_date...Time.now.utc.to_date)
 | 
			
		||||
      @pending_users_count   = User.pending.count
 | 
			
		||||
      @pending_reports_count = Report.unresolved.count
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def batch
 | 
			
		||||
      authorize :email_domain_block, :index?
 | 
			
		||||
 | 
			
		||||
      @form = Form::EmailDomainBlockBatch.new(form_email_domain_block_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
      @form.save
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize :follow_recommendation, :show?
 | 
			
		||||
 | 
			
		||||
      @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
      @form.save
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,6 +29,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def batch
 | 
			
		||||
      authorize :ip_block, :index?
 | 
			
		||||
 | 
			
		||||
      @form = Form::IpBlockBatch.new(form_ip_block_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
      @form.save
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,7 @@ module Admin
 | 
			
		|||
    PER_PAGE = 40
 | 
			
		||||
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :account, :index?
 | 
			
		||||
      authorize @account, :show?
 | 
			
		||||
 | 
			
		||||
      @accounts = RelationshipFilter.new(@account, filter_params).results.includes(:account_stat, user: [:ips, :invite_request]).page(params[:page]).per(PER_PAGE)
 | 
			
		||||
      @form     = Form::AccountBatch.new
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,20 +2,63 @@
 | 
			
		|||
 | 
			
		||||
module Admin
 | 
			
		||||
  class RolesController < BaseController
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
    before_action :set_role, except: [:index, :new, :create]
 | 
			
		||||
 | 
			
		||||
    def promote
 | 
			
		||||
      authorize @user, :promote?
 | 
			
		||||
      @user.promote!
 | 
			
		||||
      log_action :promote, @user
 | 
			
		||||
      redirect_to admin_account_path(@user.account_id)
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :user_role, :index?
 | 
			
		||||
 | 
			
		||||
      @roles = UserRole.order(position: :desc).page(params[:page])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def demote
 | 
			
		||||
      authorize @user, :demote?
 | 
			
		||||
      @user.demote!
 | 
			
		||||
      log_action :demote, @user
 | 
			
		||||
      redirect_to admin_account_path(@user.account_id)
 | 
			
		||||
    def new
 | 
			
		||||
      authorize :user_role, :create?
 | 
			
		||||
 | 
			
		||||
      @role = UserRole.new
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def create
 | 
			
		||||
      authorize :user_role, :create?
 | 
			
		||||
 | 
			
		||||
      @role = UserRole.new(resource_params)
 | 
			
		||||
      @role.current_account = current_account
 | 
			
		||||
 | 
			
		||||
      if @role.save
 | 
			
		||||
        redirect_to admin_roles_path
 | 
			
		||||
      else
 | 
			
		||||
        render :new
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def edit
 | 
			
		||||
      authorize @role, :update?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @role, :update?
 | 
			
		||||
 | 
			
		||||
      @role.current_account = current_account
 | 
			
		||||
 | 
			
		||||
      if @role.update(resource_params)
 | 
			
		||||
        redirect_to admin_roles_path
 | 
			
		||||
      else
 | 
			
		||||
        render :edit
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
      authorize @role, :destroy?
 | 
			
		||||
      @role.destroy!
 | 
			
		||||
      redirect_to admin_roles_path
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def set_role
 | 
			
		||||
      @role = UserRole.find(params[:id])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def resource_params
 | 
			
		||||
      params.require(:user_role).permit(:name, :color, :highlighted, :position, permissions_as_keys: [])
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -14,6 +14,8 @@ module Admin
 | 
			
		|||
    end
 | 
			
		||||
 | 
			
		||||
    def batch
 | 
			
		||||
      authorize :status, :index?
 | 
			
		||||
 | 
			
		||||
      @status_batch_action = Admin::StatusBatchAction.new(admin_status_batch_action_params.merge(current_account: current_account, report_id: params[:report_id], type: action_from_button))
 | 
			
		||||
      @status_batch_action.save!
 | 
			
		||||
    rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class SubscriptionsController < BaseController
 | 
			
		||||
    def index
 | 
			
		||||
      authorize :subscription, :index?
 | 
			
		||||
      @subscriptions = ordered_subscriptions.page(requested_page)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def ordered_subscriptions
 | 
			
		||||
      Subscription.order(id: :desc).includes(:account)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def requested_page
 | 
			
		||||
      params[:page].to_i
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,13 +2,15 @@
 | 
			
		|||
 | 
			
		||||
class Admin::Trends::Links::PreviewCardProvidersController < Admin::BaseController
 | 
			
		||||
  def index
 | 
			
		||||
    authorize :preview_card_provider, :index?
 | 
			
		||||
    authorize :preview_card_provider, :review?
 | 
			
		||||
 | 
			
		||||
    @preview_card_providers = filtered_preview_card_providers.page(params[:page])
 | 
			
		||||
    @form = Trends::PreviewCardProviderBatch.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def batch
 | 
			
		||||
    authorize :preview_card_provider, :review?
 | 
			
		||||
 | 
			
		||||
    @form = Trends::PreviewCardProviderBatch.new(trends_preview_card_provider_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
    @form.save
 | 
			
		||||
  rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,15 @@
 | 
			
		|||
 | 
			
		||||
class Admin::Trends::LinksController < Admin::BaseController
 | 
			
		||||
  def index
 | 
			
		||||
    authorize :preview_card, :index?
 | 
			
		||||
    authorize :preview_card, :review?
 | 
			
		||||
 | 
			
		||||
    @preview_cards = filtered_preview_cards.page(params[:page])
 | 
			
		||||
    @form          = Trends::PreviewCardBatch.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def batch
 | 
			
		||||
    authorize :preview_card, :review?
 | 
			
		||||
 | 
			
		||||
    @form = Trends::PreviewCardBatch.new(trends_preview_card_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
    @form.save
 | 
			
		||||
  rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,15 @@
 | 
			
		|||
 | 
			
		||||
class Admin::Trends::StatusesController < Admin::BaseController
 | 
			
		||||
  def index
 | 
			
		||||
    authorize :status, :index?
 | 
			
		||||
    authorize :status, :review?
 | 
			
		||||
 | 
			
		||||
    @statuses = filtered_statuses.page(params[:page])
 | 
			
		||||
    @form     = Trends::StatusBatch.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def batch
 | 
			
		||||
    authorize :status, :review?
 | 
			
		||||
 | 
			
		||||
    @form = Trends::StatusBatch.new(trends_status_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
    @form.save
 | 
			
		||||
  rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,13 +2,15 @@
 | 
			
		|||
 | 
			
		||||
class Admin::Trends::TagsController < Admin::BaseController
 | 
			
		||||
  def index
 | 
			
		||||
    authorize :tag, :index?
 | 
			
		||||
    authorize :tag, :review?
 | 
			
		||||
 | 
			
		||||
    @tags = filtered_tags.page(params[:page])
 | 
			
		||||
    @form = Trends::TagBatch.new
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def batch
 | 
			
		||||
    authorize :tag, :review?
 | 
			
		||||
 | 
			
		||||
    @form = Trends::TagBatch.new(trends_tag_batch_params.merge(current_account: current_account, action: action_from_button))
 | 
			
		||||
    @form.save
 | 
			
		||||
  rescue ActionController::ParameterMissing
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										33
									
								
								app/controllers/admin/users/roles_controller.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/controllers/admin/users/roles_controller.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,33 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class Users::RolesController < BaseController
 | 
			
		||||
    before_action :set_user
 | 
			
		||||
 | 
			
		||||
    def show
 | 
			
		||||
      authorize @user, :change_role?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def update
 | 
			
		||||
      authorize @user, :change_role?
 | 
			
		||||
 | 
			
		||||
      @user.current_account = current_account
 | 
			
		||||
 | 
			
		||||
      if @user.update(resource_params)
 | 
			
		||||
        redirect_to admin_account_path(@user.account_id), notice: I18n.t('admin.accounts.change_role.changed_msg')
 | 
			
		||||
      else
 | 
			
		||||
        render :show
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    private
 | 
			
		||||
 | 
			
		||||
    def set_user
 | 
			
		||||
      @user = User.find(params[:user_id])
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def resource_params
 | 
			
		||||
      params.require(:user).permit(:role_id)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module Admin
 | 
			
		||||
  class TwoFactorAuthenticationsController < BaseController
 | 
			
		||||
  class Users::TwoFactorAuthenticationsController < BaseController
 | 
			
		||||
    before_action :set_target_user
 | 
			
		||||
 | 
			
		||||
    def destroy
 | 
			
		||||
| 
						 | 
				
			
			@ -1,11 +1,16 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::AccountActionsController < Api::BaseController
 | 
			
		||||
  include Authorization
 | 
			
		||||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:accounts' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_account
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    authorize @account, :show?
 | 
			
		||||
 | 
			
		||||
    account_action                 = Admin::AccountAction.new(resource_params)
 | 
			
		||||
    account_action.target_account  = @account
 | 
			
		||||
    account_action.current_account = current_account
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,11 +8,11 @@ class Api::V1::Admin::AccountsController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read', :'admin:read:accounts' }, only: [:index, :show]
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'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 :verify_authorized
 | 
			
		||||
  after_action :insert_pagination_headers, only: :index
 | 
			
		||||
 | 
			
		||||
  FILTER_PARAMS = %i(
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +119,9 @@ class Api::V1::Admin::AccountsController < Api::BaseController
 | 
			
		|||
      translated_params[:status] = status.to_s if params[status].present?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    translated_params[:permissions] = 'staff' if params[:staff].present?
 | 
			
		||||
    if params[:staff].present?
 | 
			
		||||
      translated_params[:role_ids] = UserRole.that_can(:manage_reports).map(&:id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    translated_params
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,15 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::DimensionsController < Api::BaseController
 | 
			
		||||
  include Authorization
 | 
			
		||||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_dimensions
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    authorize :dashboard, :index?
 | 
			
		||||
    render json: @dimensions, each_serializer: REST::Admin::DimensionSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,10 @@ class Api::V1::Admin::DomainAllowsController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read', :'admin:read:domain_allows' }, only: [:index, :show]
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:domain_allows' }, except: [:index, :show]
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_domain_allows, only: :index
 | 
			
		||||
  before_action :set_domain_allow, only: [:show, :destroy]
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
  after_action :insert_pagination_headers, only: :index
 | 
			
		||||
 | 
			
		||||
  PAGINATION_PARAMS = %i(limit).freeze
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,10 @@ class Api::V1::Admin::DomainBlocksController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read', :'admin:read:domain_blocks' }, only: [:index, :show]
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:write', :'admin:write:domain_blocks' }, except: [:index, :show]
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_domain_blocks, only: :index
 | 
			
		||||
  before_action :set_domain_block, only: [:show, :update, :destroy]
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
  after_action :insert_pagination_headers, only: :index
 | 
			
		||||
 | 
			
		||||
  PAGINATION_PARAMS = %i(limit).freeze
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,15 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::MeasuresController < Api::BaseController
 | 
			
		||||
  include Authorization
 | 
			
		||||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_measures
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    authorize :dashboard, :index?
 | 
			
		||||
    render json: @measures, each_serializer: REST::Admin::MeasureSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,10 +8,10 @@ class Api::V1::Admin::ReportsController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read', :'admin:read:reports' }, only: [:index, :show]
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'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 :verify_authorized
 | 
			
		||||
  after_action :insert_pagination_headers, only: :index
 | 
			
		||||
 | 
			
		||||
  FILTER_PARAMS = %i(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,11 +1,15 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::RetentionController < Api::BaseController
 | 
			
		||||
  include Authorization
 | 
			
		||||
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_cohorts
 | 
			
		||||
 | 
			
		||||
  after_action :verify_authorized
 | 
			
		||||
 | 
			
		||||
  def create
 | 
			
		||||
    authorize :dashboard, :index?
 | 
			
		||||
    render json: @cohorts, each_serializer: REST::Admin::CohortSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,19 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::Trends::LinksController < Api::BaseController
 | 
			
		||||
class Api::V1::Admin::Trends::LinksController < Api::V1::Trends::LinksController
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_links
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    render json: @links, each_serializer: REST::Trends::LinkSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_links
 | 
			
		||||
    @links = Trends.links.query.limit(limit_param(10))
 | 
			
		||||
  def enabled?
 | 
			
		||||
    super || current_user&.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def links_from_trends
 | 
			
		||||
    if current_user&.can?(:manage_taxonomies)
 | 
			
		||||
      Trends.links.query
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,19 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::Trends::StatusesController < Api::BaseController
 | 
			
		||||
class Api::V1::Admin::Trends::StatusesController < Api::V1::Trends::StatusesController
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_statuses
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    render json: @statuses, each_serializer: REST::StatusSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_statuses
 | 
			
		||||
    @statuses = cache_collection(Trends.statuses.query.limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status)
 | 
			
		||||
  def enabled?
 | 
			
		||||
    super || current_user&.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def statuses_from_trends
 | 
			
		||||
    if current_user&.can?(:manage_taxonomies)
 | 
			
		||||
      Trends.statuses.query
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,17 +1,19 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Api::V1::Admin::Trends::TagsController < Api::BaseController
 | 
			
		||||
class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
 | 
			
		||||
  before_action -> { authorize_if_got_token! :'admin:read' }
 | 
			
		||||
  before_action :require_staff!
 | 
			
		||||
  before_action :set_tags
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    render json: @tags, each_serializer: REST::Admin::TagSerializer
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def set_tags
 | 
			
		||||
    @tags = Trends.tags.query.limit(limit_param(10))
 | 
			
		||||
  def enabled?
 | 
			
		||||
    super || current_user&.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tags_from_trends
 | 
			
		||||
    if current_user&.can?(:manage_taxonomies)
 | 
			
		||||
      Trends.tags.query
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,10 +13,14 @@ class Api::V1::Trends::LinksController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def enabled?
 | 
			
		||||
    Setting.trends
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_links
 | 
			
		||||
    @links = begin
 | 
			
		||||
      if Setting.trends
 | 
			
		||||
        links_from_trends
 | 
			
		||||
      if enabled?
 | 
			
		||||
        links_from_trends.offset(offset_param).limit(limit_param(DEFAULT_LINKS_LIMIT))
 | 
			
		||||
      else
 | 
			
		||||
        []
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +28,7 @@ class Api::V1::Trends::LinksController < Api::BaseController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def links_from_trends
 | 
			
		||||
    Trends.links.query.allowed.in_locale(content_locale).offset(offset_param).limit(limit_param(DEFAULT_LINKS_LIMIT))
 | 
			
		||||
    Trends.links.query.allowed.in_locale(content_locale)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def insert_pagination_headers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,10 +11,14 @@ class Api::V1::Trends::StatusesController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def enabled?
 | 
			
		||||
    Setting.trends
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_statuses
 | 
			
		||||
    @statuses = begin
 | 
			
		||||
      if Setting.trends
 | 
			
		||||
        cache_collection(statuses_from_trends, Status)
 | 
			
		||||
      if enabled?
 | 
			
		||||
        cache_collection(statuses_from_trends.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT)), Status)
 | 
			
		||||
      else
 | 
			
		||||
        []
 | 
			
		||||
      end
 | 
			
		||||
| 
						 | 
				
			
			@ -24,7 +28,7 @@ class Api::V1::Trends::StatusesController < Api::BaseController
 | 
			
		|||
  def statuses_from_trends
 | 
			
		||||
    scope = Trends.statuses.query.allowed.in_locale(content_locale)
 | 
			
		||||
    scope = scope.filtered_for(current_account) if user_signed_in?
 | 
			
		||||
    scope.offset(offset_param).limit(limit_param(DEFAULT_STATUSES_LIMIT))
 | 
			
		||||
    scope
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def insert_pagination_headers
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,16 +13,24 @@ class Api::V1::Trends::TagsController < Api::BaseController
 | 
			
		|||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def enabled?
 | 
			
		||||
    Setting.trends
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_tags
 | 
			
		||||
    @tags = begin
 | 
			
		||||
      if Setting.trends
 | 
			
		||||
        Trends.tags.query.allowed.offset(offset_param).limit(limit_param(DEFAULT_TAGS_LIMIT))
 | 
			
		||||
      if enabled?
 | 
			
		||||
        tags_from_trends.offset(offset_param).limit(limit_param(DEFAULT_TAGS_LIMIT))
 | 
			
		||||
      else
 | 
			
		||||
        []
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def tags_from_trends
 | 
			
		||||
    Trends.tags.query.allowed
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def insert_pagination_headers
 | 
			
		||||
    set_pagination_headers(next_path, prev_path)
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,6 +11,7 @@ class Api::V2::Admin::AccountsController < Api::V1::Admin::AccountsController
 | 
			
		|||
    email
 | 
			
		||||
    ip
 | 
			
		||||
    invited_by
 | 
			
		||||
    role_ids
 | 
			
		||||
  ).freeze
 | 
			
		||||
 | 
			
		||||
  PAGINATION_PARAMS = (%i(limit) + FILTER_PARAMS).freeze
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +19,17 @@ class Api::V2::Admin::AccountsController < Api::V1::Admin::AccountsController
 | 
			
		|||
  private
 | 
			
		||||
 | 
			
		||||
  def filtered_accounts
 | 
			
		||||
    AccountFilter.new(filter_params).results
 | 
			
		||||
    AccountFilter.new(translated_filter_params).results
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def translated_filter_params
 | 
			
		||||
    translated_params = filter_params.slice(*AccountFilter::KEYS)
 | 
			
		||||
 | 
			
		||||
    if params[:permissions] == 'staff'
 | 
			
		||||
      translated_params[:role_ids] = UserRole.that_can(:manage_reports).map(&:id)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    translated_params
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def filter_params
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,14 +56,6 @@ class ApplicationController < ActionController::Base
 | 
			
		|||
    store_location_for(:user, request.url) unless [:json, :rss].include?(request.format&.to_sym)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_admin!
 | 
			
		||||
    forbidden unless current_user&.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_staff!
 | 
			
		||||
    forbidden unless current_user&.staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def require_functional!
 | 
			
		||||
    redirect_to edit_user_registration_path unless current_user.functional?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,6 @@ class CustomCssController < ApplicationController
 | 
			
		|||
  def show
 | 
			
		||||
    expires_in 3.minutes, public: true
 | 
			
		||||
    request.session_options[:skip] = true
 | 
			
		||||
    render plain: Setting.custom_css || '', content_type: 'text/css'
 | 
			
		||||
    render content_type: 'text/css'
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,21 +61,13 @@ module AccountsHelper
 | 
			
		|||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def account_badge(account, all: false)
 | 
			
		||||
  def account_badge(account)
 | 
			
		||||
    if account.bot?
 | 
			
		||||
      content_tag(:div, content_tag(:div, t('accounts.roles.bot'), class: 'account-role bot'), class: 'roles')
 | 
			
		||||
    elsif account.group?
 | 
			
		||||
      content_tag(:div, content_tag(:div, t('accounts.roles.group'), class: 'account-role group'), class: 'roles')
 | 
			
		||||
    elsif (Setting.show_staff_badge && account.user_staff?) || all
 | 
			
		||||
      content_tag(:div, class: 'roles') do
 | 
			
		||||
        if all && !account.user_staff?
 | 
			
		||||
          content_tag(:div, t('admin.accounts.roles.user'), class: 'account-role')
 | 
			
		||||
        elsif account.user_admin?
 | 
			
		||||
          content_tag(:div, t('accounts.roles.admin'), class: 'account-role admin')
 | 
			
		||||
        elsif account.user_moderator?
 | 
			
		||||
          content_tag(:div, t('accounts.roles.moderator'), class: 'account-role moderator')
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
    elsif account.user_role&.highlighted?
 | 
			
		||||
      content_tag(:div, content_tag(:div, account.user_role.name, class: "account-role user-role-#{account.user_role.id}"), class: 'roles')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,8 +6,9 @@ import IconButton from './icon_button';
 | 
			
		|||
import DropdownMenuContainer from '../containers/dropdown_menu_container';
 | 
			
		||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
			
		||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
			
		||||
import { me, isStaff } from '../initial_state';
 | 
			
		||||
import { me } from '../initial_state';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { PERMISSION_MANAGE_USERS } from 'mastodon/permissions';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  delete: { id: 'status.delete', defaultMessage: 'Delete' },
 | 
			
		||||
| 
						 | 
				
			
			@ -55,6 +56,7 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
			
		|||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
    router: PropTypes.object,
 | 
			
		||||
    identity: PropTypes.object,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
| 
						 | 
				
			
			@ -306,7 +308,7 @@ class StatusActionBar extends ImmutablePureComponent {
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (isStaff) {
 | 
			
		||||
      if ((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) {
 | 
			
		||||
        menu.push(null);
 | 
			
		||||
        menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
 | 
			
		||||
        menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses?id=${status.get('id')}` });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ const createIdentityContext = state => ({
 | 
			
		|||
  signedIn: !!state.meta.me,
 | 
			
		||||
  accountId: state.meta.me,
 | 
			
		||||
  accessToken: state.meta.access_token,
 | 
			
		||||
  permissions: state.role.permissions,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default class Mastodon extends React.PureComponent {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
 | 
			
		|||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 | 
			
		||||
import Button from 'mastodon/components/button';
 | 
			
		||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
			
		||||
import { autoPlayGif, me, isStaff } from 'mastodon/initial_state';
 | 
			
		||||
import { autoPlayGif, me } from 'mastodon/initial_state';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import Icon from 'mastodon/components/icon';
 | 
			
		||||
import IconButton from 'mastodon/components/icon_button';
 | 
			
		||||
| 
						 | 
				
			
			@ -14,6 +14,7 @@ import ShortNumber from 'mastodon/components/short_number';
 | 
			
		|||
import { NavLink } from 'react-router-dom';
 | 
			
		||||
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
 | 
			
		||||
import AccountNoteContainer from '../containers/account_note_container';
 | 
			
		||||
import { PERMISSION_MANAGE_USERS } from 'mastodon/permissions';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +65,10 @@ const dateFormatOptions = {
 | 
			
		|||
export default @injectIntl
 | 
			
		||||
class Header extends ImmutablePureComponent {
 | 
			
		||||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
    identity: PropTypes.object,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
    account: ImmutablePropTypes.map,
 | 
			
		||||
    identity_props: ImmutablePropTypes.list,
 | 
			
		||||
| 
						 | 
				
			
			@ -241,7 +246,7 @@ class Header extends ImmutablePureComponent {
 | 
			
		|||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (account.get('id') !== me && isStaff) {
 | 
			
		||||
    if (account.get('id') !== me && (this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) {
 | 
			
		||||
      menu.push(null);
 | 
			
		||||
      menu.push({ text: intl.formatMessage(messages.admin_account, { name: account.get('username') }), href: `/admin/accounts/${account.get('id')}` });
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,10 +5,14 @@ import { FormattedMessage } from 'react-intl';
 | 
			
		|||
import ClearColumnButton from './clear_column_button';
 | 
			
		||||
import GrantPermissionButton from './grant_permission_button';
 | 
			
		||||
import SettingToggle from './setting_toggle';
 | 
			
		||||
import { isStaff } from 'mastodon/initial_state';
 | 
			
		||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
 | 
			
		||||
 | 
			
		||||
export default class ColumnSettings extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
    identity: PropTypes.object,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
    settings: ImmutablePropTypes.map.isRequired,
 | 
			
		||||
    pushSettings: ImmutablePropTypes.map.isRequired,
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +170,7 @@ export default class ColumnSettings extends React.PureComponent {
 | 
			
		|||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        {isStaff && (
 | 
			
		||||
        {(this.context.identity.permissions & PERMISSION_MANAGE_USERS === PERMISSION_MANAGE_USERS) && (
 | 
			
		||||
          <div role='group' aria-labelledby='notifications-admin-sign-up'>
 | 
			
		||||
            <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.sign_up' defaultMessage='New sign-ups:' /></span>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -179,7 +183,7 @@ export default class ColumnSettings extends React.PureComponent {
 | 
			
		|||
          </div>
 | 
			
		||||
        )}
 | 
			
		||||
 | 
			
		||||
        {isStaff && (
 | 
			
		||||
        {(this.context.identity.permissions & PERMISSION_MANAGE_REPORTS === PERMISSION_MANAGE_REPORTS) && (
 | 
			
		||||
          <div role='group' aria-labelledby='notifications-admin-report'>
 | 
			
		||||
            <span id='notifications-status' className='column-settings__section'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></span>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -5,8 +5,9 @@ import IconButton from '../../../components/icon_button';
 | 
			
		|||
import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
 | 
			
		||||
import { defineMessages, injectIntl } from 'react-intl';
 | 
			
		||||
import { me, isStaff } from '../../../initial_state';
 | 
			
		||||
import { me } from '../../../initial_state';
 | 
			
		||||
import classNames from 'classnames';
 | 
			
		||||
import { PERMISSION_MANAGE_USERS } from 'mastodon/permissions';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  delete: { id: 'status.delete', defaultMessage: 'Delete' },
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +51,7 @@ class ActionBar extends React.PureComponent {
 | 
			
		|||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
    router: PropTypes.object,
 | 
			
		||||
    identity: PropTypes.object,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
| 
						 | 
				
			
			@ -248,7 +250,7 @@ class ActionBar extends React.PureComponent {
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (isStaff) {
 | 
			
		||||
      if ((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) {
 | 
			
		||||
        menu.push(null);
 | 
			
		||||
        menu.push({ text: intl.formatMessage(messages.admin_account, { name: status.getIn(['account', 'username']) }), href: `/admin/accounts/${status.getIn(['account', 'id'])}` });
 | 
			
		||||
        menu.push({ text: intl.formatMessage(messages.admin_status), href: `/admin/accounts/${status.getIn(['account', 'id'])}/statuses?id=${status.get('id')}` });
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,9 +3,10 @@ import React from 'react';
 | 
			
		|||
import PropTypes from 'prop-types';
 | 
			
		||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 | 
			
		||||
import { Link } from 'react-router-dom';
 | 
			
		||||
import { invitesEnabled, limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'mastodon/initial_state';
 | 
			
		||||
import { limitedFederationMode, version, repository, source_url, profile_directory as profileDirectory } from 'mastodon/initial_state';
 | 
			
		||||
import { logOut } from 'mastodon/utils/log_out';
 | 
			
		||||
import { openModal } from 'mastodon/actions/modal';
 | 
			
		||||
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +28,10 @@ export default @injectIntl
 | 
			
		|||
@connect(null, mapDispatchToProps)
 | 
			
		||||
class LinkFooter extends React.PureComponent {
 | 
			
		||||
 | 
			
		||||
  static contextTypes = {
 | 
			
		||||
    identity: PropTypes.object,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  static propTypes = {
 | 
			
		||||
    withHotkeys: PropTypes.bool,
 | 
			
		||||
    onLogout: PropTypes.func.isRequired,
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +53,7 @@ class LinkFooter extends React.PureComponent {
 | 
			
		|||
    return (
 | 
			
		||||
      <div className='getting-started__footer'>
 | 
			
		||||
        <ul>
 | 
			
		||||
          {invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
 | 
			
		||||
          {((this.context.identity.permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS) && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
 | 
			
		||||
          {withHotkeys && <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li>}
 | 
			
		||||
          <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li>
 | 
			
		||||
          {!limitedFederationMode && <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,14 +12,12 @@ export const boostModal = getMeta('boost_modal');
 | 
			
		|||
export const deleteModal = getMeta('delete_modal');
 | 
			
		||||
export const me = getMeta('me');
 | 
			
		||||
export const searchEnabled = getMeta('search_enabled');
 | 
			
		||||
export const invitesEnabled = getMeta('invites_enabled');
 | 
			
		||||
export const limitedFederationMode = getMeta('limited_federation_mode');
 | 
			
		||||
export const repository = getMeta('repository');
 | 
			
		||||
export const source_url = getMeta('source_url');
 | 
			
		||||
export const version = getMeta('version');
 | 
			
		||||
export const mascot = getMeta('mascot');
 | 
			
		||||
export const profile_directory = getMeta('profile_directory');
 | 
			
		||||
export const isStaff = getMeta('is_staff');
 | 
			
		||||
export const forceSingleColumn = !getMeta('advanced_layout');
 | 
			
		||||
export const useBlurhash = getMeta('use_blurhash');
 | 
			
		||||
export const usePendingItems = getMeta('use_pending_items');
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										3
									
								
								app/javascript/mastodon/permissions.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/javascript/mastodon/permissions.js
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
export const PERMISSION_INVITE_USERS   = 0x0000000000010000;
 | 
			
		||||
export const PERMISSION_MANAGE_USERS   = 0x0000000000000400;
 | 
			
		||||
export const PERMISSION_MANAGE_REPORTS = 0x0000000000000010;
 | 
			
		||||
| 
						 | 
				
			
			@ -7,12 +7,13 @@ const initialState = ImmutableMap({
 | 
			
		|||
  streaming_api_base_url: null,
 | 
			
		||||
  access_token: null,
 | 
			
		||||
  layout: layoutFromWindow(),
 | 
			
		||||
  permissions: '0',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default function meta(state = initialState, action) {
 | 
			
		||||
  switch(action.type) {
 | 
			
		||||
  case STORE_HYDRATE:
 | 
			
		||||
    return state.merge(action.state.get('meta'));
 | 
			
		||||
    return state.merge(action.state.get('meta')).set('permissions', action.state.getIn(['role', 'permissions']));
 | 
			
		||||
  case APP_LAYOUT_CHANGE:
 | 
			
		||||
    return state.set('layout', action.layout);
 | 
			
		||||
  default:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -924,6 +924,10 @@ a.name-tag,
 | 
			
		|||
  margin-top: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.user-role {
 | 
			
		||||
  color: var(--user-role-accent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.announcements-list,
 | 
			
		||||
.filters-list {
 | 
			
		||||
  border: 1px solid lighten($ui-base-color, 4%);
 | 
			
		||||
| 
						 | 
				
			
			@ -960,6 +964,17 @@ a.name-tag,
 | 
			
		|||
    &__meta {
 | 
			
		||||
      padding: 0 15px;
 | 
			
		||||
      color: $dark-text-color;
 | 
			
		||||
 | 
			
		||||
      a {
 | 
			
		||||
        color: inherit;
 | 
			
		||||
        text-decoration: underline;
 | 
			
		||||
 | 
			
		||||
        &:hover,
 | 
			
		||||
        &:focus,
 | 
			
		||||
        &:active {
 | 
			
		||||
          text-decoration: none;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &__action-bar {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -256,6 +256,10 @@ code {
 | 
			
		|||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .input.with_block_label.user_role_permissions_as_keys ul {
 | 
			
		||||
    columns: unset;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .input.datetime .label_input select {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    width: auto;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,11 +8,11 @@ class Admin::SystemCheck
 | 
			
		|||
    Admin::SystemCheck::ElasticsearchCheck,
 | 
			
		||||
  ].freeze
 | 
			
		||||
 | 
			
		||||
  def self.perform
 | 
			
		||||
  def self.perform(current_user)
 | 
			
		||||
    ACTIVE_CHECKS.each_with_object([]) do |klass, arr|
 | 
			
		||||
      check = klass.new
 | 
			
		||||
      check = klass.new(current_user)
 | 
			
		||||
 | 
			
		||||
      if check.pass?
 | 
			
		||||
      if check.skip? || check.pass?
 | 
			
		||||
        arr
 | 
			
		||||
      else
 | 
			
		||||
        arr << check.message
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,16 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::SystemCheck::BaseCheck
 | 
			
		||||
  attr_reader :current_user
 | 
			
		||||
 | 
			
		||||
  def initialize(current_user)
 | 
			
		||||
    @current_user = current_user
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def skip?
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pass?
 | 
			
		||||
    raise NotImplementedError
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,10 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::SystemCheck::DatabaseSchemaCheck < Admin::SystemCheck::BaseCheck
 | 
			
		||||
  def skip?
 | 
			
		||||
    !current_user.can?(:view_devops)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pass?
 | 
			
		||||
    !ActiveRecord::Base.connection.migration_context.needs_migration?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,10 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class Admin::SystemCheck::ElasticsearchCheck < Admin::SystemCheck::BaseCheck
 | 
			
		||||
  def skip?
 | 
			
		||||
    !current_user.can?(:view_devops)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pass?
 | 
			
		||||
    return true unless Chewy.enabled?
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -32,8 +36,4 @@ class Admin::SystemCheck::ElasticsearchCheck < Admin::SystemCheck::BaseCheck
 | 
			
		|||
  def compatible_version?
 | 
			
		||||
    Gem::Version.new(running_version) >= Gem::Version.new(required_version)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def missing_queues
 | 
			
		||||
    @missing_queues ||= Sidekiq::ProcessSet.new.reduce(SIDEKIQ_QUEUES) { |queues, process| queues - process['queues'] }
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,10 @@
 | 
			
		|||
class Admin::SystemCheck::RulesCheck < Admin::SystemCheck::BaseCheck
 | 
			
		||||
  include RoutingHelper
 | 
			
		||||
 | 
			
		||||
  def skip?
 | 
			
		||||
    !current_user.can?(:manage_rules)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pass?
 | 
			
		||||
    Rule.kept.exists?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -9,6 +9,10 @@ class Admin::SystemCheck::SidekiqProcessCheck < Admin::SystemCheck::BaseCheck
 | 
			
		|||
    scheduler
 | 
			
		||||
  ).freeze
 | 
			
		||||
 | 
			
		||||
  def skip?
 | 
			
		||||
    !current_user.can?(:view_devops)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def pass?
 | 
			
		||||
    missing_queues.empty?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -116,7 +116,7 @@ class Account < ApplicationRecord
 | 
			
		|||
  scope :by_recent_status, -> { order(Arel.sql('(case when account_stats.last_status_at is null then 1 else 0 end) asc, account_stats.last_status_at desc, accounts.id desc')) }
 | 
			
		||||
  scope :by_recent_sign_in, -> { order(Arel.sql('(case when users.current_sign_in_at is null then 1 else 0 end) asc, users.current_sign_in_at desc, accounts.id desc')) }
 | 
			
		||||
  scope :popular, -> { order('account_stats.followers_count desc') }
 | 
			
		||||
  scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches('%.' + domain))) }
 | 
			
		||||
  scope :by_domain_and_subdomains, ->(domain) { where(domain: domain).or(where(arel_table[:domain].matches("%.#{domain}"))) }
 | 
			
		||||
  scope :not_excluded_by_account, ->(account) { where.not(id: account.excluded_from_timeline_account_ids) }
 | 
			
		||||
  scope :not_domain_blocked_by_account, ->(account) { where(arel_table[:domain].eq(nil).or(arel_table[:domain].not_in(account.excluded_from_timeline_domains))) }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -132,9 +132,6 @@ class Account < ApplicationRecord
 | 
			
		|||
           :unconfirmed?,
 | 
			
		||||
           :unconfirmed_or_pending?,
 | 
			
		||||
           :role,
 | 
			
		||||
           :admin?,
 | 
			
		||||
           :moderator?,
 | 
			
		||||
           :staff?,
 | 
			
		||||
           :locale,
 | 
			
		||||
           :shows_application?,
 | 
			
		||||
           to: :user,
 | 
			
		||||
| 
						 | 
				
			
			@ -454,7 +451,7 @@ class Account < ApplicationRecord
 | 
			
		|||
      DeliveryFailureTracker.without_unavailable(urls)
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def search_for(terms, limit = 10, offset = 0)
 | 
			
		||||
    def search_for(terms, limit: 10, offset: 0)
 | 
			
		||||
      tsquery = generate_query_for_search(terms)
 | 
			
		||||
 | 
			
		||||
      sql = <<-SQL.squish
 | 
			
		||||
| 
						 | 
				
			
			@ -476,7 +473,7 @@ class Account < ApplicationRecord
 | 
			
		|||
      records
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def advanced_search_for(terms, account, limit = 10, following = false, offset = 0)
 | 
			
		||||
    def advanced_search_for(terms, account, limit: 10, following: false, offset: 0)
 | 
			
		||||
      tsquery = generate_query_for_search(terms)
 | 
			
		||||
      sql = advanced_search_for_sql_template(following)
 | 
			
		||||
      records = find_by_sql([sql, id: account.id, limit: limit, offset: offset, tsquery: tsquery])
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,7 @@ class AccountFilter
 | 
			
		|||
  KEYS = %i(
 | 
			
		||||
    origin
 | 
			
		||||
    status
 | 
			
		||||
    permissions
 | 
			
		||||
    role_ids
 | 
			
		||||
    username
 | 
			
		||||
    by_domain
 | 
			
		||||
    display_name
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +26,7 @@ class AccountFilter
 | 
			
		|||
    params.each do |key, value|
 | 
			
		||||
      next if key.to_s == 'page'
 | 
			
		||||
 | 
			
		||||
      scope.merge!(scope_for(key, value.to_s.strip)) if value.present?
 | 
			
		||||
      scope.merge!(scope_for(key, value)) if value.present?
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    scope
 | 
			
		||||
| 
						 | 
				
			
			@ -38,18 +38,18 @@ class AccountFilter
 | 
			
		|||
    case key.to_s
 | 
			
		||||
    when 'origin'
 | 
			
		||||
      origin_scope(value)
 | 
			
		||||
    when 'permissions'
 | 
			
		||||
      permissions_scope(value)
 | 
			
		||||
    when 'role_ids'
 | 
			
		||||
      role_scope(value)
 | 
			
		||||
    when 'status'
 | 
			
		||||
      status_scope(value)
 | 
			
		||||
    when 'by_domain'
 | 
			
		||||
      Account.where(domain: value)
 | 
			
		||||
      Account.where(domain: value.to_s)
 | 
			
		||||
    when 'username'
 | 
			
		||||
      Account.matches_username(value)
 | 
			
		||||
      Account.matches_username(value.to_s)
 | 
			
		||||
    when 'display_name'
 | 
			
		||||
      Account.matches_display_name(value)
 | 
			
		||||
      Account.matches_display_name(value.to_s)
 | 
			
		||||
    when 'email'
 | 
			
		||||
      accounts_with_users.merge(User.matches_email(value))
 | 
			
		||||
      accounts_with_users.merge(User.matches_email(value.to_s))
 | 
			
		||||
    when 'ip'
 | 
			
		||||
      valid_ip?(value) ? accounts_with_users.merge(User.matches_ip(value).group('users.id, accounts.id')) : Account.none
 | 
			
		||||
    when 'invited_by'
 | 
			
		||||
| 
						 | 
				
			
			@ -104,13 +104,8 @@ class AccountFilter
 | 
			
		|||
    Account.left_joins(user: :invite).merge(Invite.where(user_id: value.to_s))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def permissions_scope(value)
 | 
			
		||||
    case value.to_s
 | 
			
		||||
    when 'staff'
 | 
			
		||||
      accounts_with_users.merge(User.staff)
 | 
			
		||||
    else
 | 
			
		||||
      raise "Unknown permissions: #{value}"
 | 
			
		||||
    end
 | 
			
		||||
  def role_scope(value)
 | 
			
		||||
    accounts_with_users.merge(User.where(role_id: Array(value).map(&:to_s)))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def accounts_with_users
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +113,7 @@ class AccountFilter
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def valid_ip?(value)
 | 
			
		||||
    IPAddr.new(value) && true
 | 
			
		||||
    IPAddr.new(value.to_s) && true
 | 
			
		||||
  rescue IPAddr::InvalidAddressError
 | 
			
		||||
    false
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,68 +0,0 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
module UserRoles
 | 
			
		||||
  extend ActiveSupport::Concern
 | 
			
		||||
 | 
			
		||||
  included do
 | 
			
		||||
    scope :admins, -> { where(admin: true) }
 | 
			
		||||
    scope :moderators, -> { where(moderator: true) }
 | 
			
		||||
    scope :staff, -> { admins.or(moderators) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def staff?
 | 
			
		||||
    admin? || moderator?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role=(value)
 | 
			
		||||
    case value
 | 
			
		||||
    when 'admin'
 | 
			
		||||
      self.admin     = true
 | 
			
		||||
      self.moderator = false
 | 
			
		||||
    when 'moderator'
 | 
			
		||||
      self.admin     = false
 | 
			
		||||
      self.moderator = true
 | 
			
		||||
    else
 | 
			
		||||
      self.admin     = false
 | 
			
		||||
      self.moderator = false
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    if admin?
 | 
			
		||||
      'admin'
 | 
			
		||||
    elsif moderator?
 | 
			
		||||
      'moderator'
 | 
			
		||||
    else
 | 
			
		||||
      'user'
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role?(role)
 | 
			
		||||
    case role
 | 
			
		||||
    when 'user'
 | 
			
		||||
      true
 | 
			
		||||
    when 'moderator'
 | 
			
		||||
      staff?
 | 
			
		||||
    when 'admin'
 | 
			
		||||
      admin?
 | 
			
		||||
    else
 | 
			
		||||
      false
 | 
			
		||||
    end
 | 
			
		||||
  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
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -15,10 +15,8 @@ class Form::AdminSettings
 | 
			
		|||
    closed_registrations_message
 | 
			
		||||
    open_deletion
 | 
			
		||||
    timeline_preview
 | 
			
		||||
    show_staff_badge
 | 
			
		||||
    bootstrap_timeline_accounts
 | 
			
		||||
    theme
 | 
			
		||||
    min_invite_role
 | 
			
		||||
    activity_api_enabled
 | 
			
		||||
    peers_api_enabled
 | 
			
		||||
    show_known_fediverse_at_about_page
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +37,6 @@ class Form::AdminSettings
 | 
			
		|||
  BOOLEAN_KEYS = %i(
 | 
			
		||||
    open_deletion
 | 
			
		||||
    timeline_preview
 | 
			
		||||
    show_staff_badge
 | 
			
		||||
    activity_api_enabled
 | 
			
		||||
    peers_api_enabled
 | 
			
		||||
    show_known_fediverse_at_about_page
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +59,6 @@ class Form::AdminSettings
 | 
			
		|||
  validates :site_short_description, :site_description, html: { wrap_with: :p }
 | 
			
		||||
  validates :site_extended_description, :site_terms, :closed_registrations_message, html: true
 | 
			
		||||
  validates :registrations_mode, inclusion: { in: %w(open approved none) }
 | 
			
		||||
  validates :min_invite_role, inclusion: { in: %w(disabled user moderator admin) }
 | 
			
		||||
  validates :site_contact_email, :site_contact_username, presence: true
 | 
			
		||||
  validates :site_contact_username, existing_username: true
 | 
			
		||||
  validates :bootstrap_timeline_accounts, existing_username: { multiple: true }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,7 +34,7 @@ module Trends
 | 
			
		|||
 | 
			
		||||
    return if links_requiring_review.empty? && tags_requiring_review.empty? && statuses_requiring_review.empty?
 | 
			
		||||
 | 
			
		||||
    User.staff.includes(:account).find_each do |user|
 | 
			
		||||
    User.those_who_can(:manage_taxonomies).includes(:account).find_each do |user|
 | 
			
		||||
      AdminMailer.new_trends(user.account, links_requiring_review, tags_requiring_review, statuses_requiring_review).deliver_later! if user.allows_trends_review_emails?
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,6 +37,7 @@
 | 
			
		|||
#  sign_in_token_sent_at     :datetime
 | 
			
		||||
#  webauthn_id               :string
 | 
			
		||||
#  sign_up_ip                :inet
 | 
			
		||||
#  role_id                   :bigint(8)
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class User < ApplicationRecord
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +51,6 @@ class User < ApplicationRecord
 | 
			
		|||
  )
 | 
			
		||||
 | 
			
		||||
  include Settings::Extend
 | 
			
		||||
  include UserRoles
 | 
			
		||||
  include Redisable
 | 
			
		||||
  include LanguagesHelper
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -79,6 +79,7 @@ class User < ApplicationRecord
 | 
			
		|||
  belongs_to :account, inverse_of: :user
 | 
			
		||||
  belongs_to :invite, counter_cache: :uses, optional: true
 | 
			
		||||
  belongs_to :created_by_application, class_name: 'Doorkeeper::Application', optional: true
 | 
			
		||||
  belongs_to :role, class_name: 'UserRole', optional: true
 | 
			
		||||
  accepts_nested_attributes_for :account
 | 
			
		||||
 | 
			
		||||
  has_many :applications, class_name: 'Doorkeeper::Application', as: :owner
 | 
			
		||||
| 
						 | 
				
			
			@ -103,6 +104,7 @@ class User < ApplicationRecord
 | 
			
		|||
  validates_with RegistrationFormTimeValidator, on: :create
 | 
			
		||||
  validates :website, absence: true, on: :create
 | 
			
		||||
  validates :confirm_password, absence: true, on: :create
 | 
			
		||||
  validate :validate_role_elevation
 | 
			
		||||
 | 
			
		||||
  scope :recent, -> { order(id: :desc) }
 | 
			
		||||
  scope :pending, -> { where(approved: false) }
 | 
			
		||||
| 
						 | 
				
			
			@ -117,6 +119,7 @@ class User < ApplicationRecord
 | 
			
		|||
  scope :emailable, -> { confirmed.enabled.joins(:account).merge(Account.searchable) }
 | 
			
		||||
 | 
			
		||||
  before_validation :sanitize_languages
 | 
			
		||||
  before_validation :sanitize_role
 | 
			
		||||
  before_create :set_approved
 | 
			
		||||
  after_commit :send_pending_devise_notifications
 | 
			
		||||
  after_create_commit :trigger_webhooks
 | 
			
		||||
| 
						 | 
				
			
			@ -135,8 +138,28 @@ class User < ApplicationRecord
 | 
			
		|||
           :disable_swiping, :always_send_emails,
 | 
			
		||||
           to: :settings, prefix: :setting, allow_nil: false
 | 
			
		||||
 | 
			
		||||
  delegate :can?, to: :role
 | 
			
		||||
 | 
			
		||||
  attr_reader :invite_code
 | 
			
		||||
  attr_writer :external, :bypass_invite_request_check
 | 
			
		||||
  attr_writer :external, :bypass_invite_request_check, :current_account
 | 
			
		||||
 | 
			
		||||
  def self.those_who_can(*any_of_privileges)
 | 
			
		||||
    matching_role_ids = UserRole.that_can(*any_of_privileges).map(&:id)
 | 
			
		||||
 | 
			
		||||
    if matching_role_ids.empty?
 | 
			
		||||
      none
 | 
			
		||||
    else
 | 
			
		||||
      where(role_id: matching_role_ids)
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    if role_id.nil?
 | 
			
		||||
      UserRole.everyone
 | 
			
		||||
    else
 | 
			
		||||
      super
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def confirmed?
 | 
			
		||||
    confirmed_at.present?
 | 
			
		||||
| 
						 | 
				
			
			@ -441,6 +464,11 @@ class User < ApplicationRecord
 | 
			
		|||
    self.chosen_languages = nil if chosen_languages.empty?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def sanitize_role
 | 
			
		||||
    return if role.nil?
 | 
			
		||||
    self.role = nil if role.everyone?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def prepare_new_user!
 | 
			
		||||
    BootstrapTimelineWorker.perform_async(account_id)
 | 
			
		||||
    ActivityTracker.increment('activity:accounts:local')
 | 
			
		||||
| 
						 | 
				
			
			@ -453,7 +481,7 @@ class User < ApplicationRecord
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def notify_staff_about_pending_account!
 | 
			
		||||
    User.staff.includes(:account).find_each do |u|
 | 
			
		||||
    User.those_who_can(:manage_users).includes(:account).find_each do |u|
 | 
			
		||||
      next unless u.allows_pending_account_emails?
 | 
			
		||||
      AdminMailer.new_pending_account(u.account, self).deliver_later
 | 
			
		||||
    end
 | 
			
		||||
| 
						 | 
				
			
			@ -471,6 +499,10 @@ class User < ApplicationRecord
 | 
			
		|||
    email_changed? && !external? && !(Rails.env.test? || Rails.env.development?)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_role_elevation
 | 
			
		||||
    errors.add(:role_id, :elevated) if defined?(@current_account) && role&.overrides?(@current_account&.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invite_text_required?
 | 
			
		||||
    Setting.require_invite_text && !invited? && !external? && !bypass_invite_request_check?
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										179
									
								
								app/models/user_role.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								app/models/user_role.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,179 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
# == Schema Information
 | 
			
		||||
#
 | 
			
		||||
# Table name: user_roles
 | 
			
		||||
#
 | 
			
		||||
#  id          :bigint(8)        not null, primary key
 | 
			
		||||
#  name        :string           default(""), not null
 | 
			
		||||
#  color       :string           default(""), not null
 | 
			
		||||
#  position    :integer          default(0), not null
 | 
			
		||||
#  permissions :bigint(8)        default(0), not null
 | 
			
		||||
#  highlighted :boolean          default(FALSE), not null
 | 
			
		||||
#  created_at  :datetime         not null
 | 
			
		||||
#  updated_at  :datetime         not null
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
class UserRole < ApplicationRecord
 | 
			
		||||
  FLAGS = {
 | 
			
		||||
    administrator: (1 << 0),
 | 
			
		||||
    view_devops: (1 << 1),
 | 
			
		||||
    view_audit_log: (1 << 2),
 | 
			
		||||
    view_dashboard: (1 << 3),
 | 
			
		||||
    manage_reports: (1 << 4),
 | 
			
		||||
    manage_federation: (1 << 5),
 | 
			
		||||
    manage_settings: (1 << 6),
 | 
			
		||||
    manage_blocks: (1 << 7),
 | 
			
		||||
    manage_taxonomies: (1 << 8),
 | 
			
		||||
    manage_appeals: (1 << 9),
 | 
			
		||||
    manage_users: (1 << 10),
 | 
			
		||||
    manage_invites: (1 << 11),
 | 
			
		||||
    manage_rules: (1 << 12),
 | 
			
		||||
    manage_announcements: (1 << 13),
 | 
			
		||||
    manage_custom_emojis: (1 << 14),
 | 
			
		||||
    manage_webhooks: (1 << 15),
 | 
			
		||||
    invite_users: (1 << 16),
 | 
			
		||||
    manage_roles: (1 << 17),
 | 
			
		||||
    manage_user_access: (1 << 18),
 | 
			
		||||
    delete_user_data: (1 << 19),
 | 
			
		||||
  }.freeze
 | 
			
		||||
 | 
			
		||||
  module Flags
 | 
			
		||||
    NONE = 0
 | 
			
		||||
    ALL  = FLAGS.values.reduce(&:|)
 | 
			
		||||
 | 
			
		||||
    DEFAULT = FLAGS[:invite_users]
 | 
			
		||||
 | 
			
		||||
    CATEGORIES = {
 | 
			
		||||
      invites: %i(
 | 
			
		||||
        invite_users
 | 
			
		||||
      ).freeze,
 | 
			
		||||
 | 
			
		||||
      moderation: %w(
 | 
			
		||||
        view_dashboard
 | 
			
		||||
        view_audit_log
 | 
			
		||||
        manage_users
 | 
			
		||||
        manage_user_access
 | 
			
		||||
        delete_user_data
 | 
			
		||||
        manage_reports
 | 
			
		||||
        manage_appeals
 | 
			
		||||
        manage_federation
 | 
			
		||||
        manage_blocks
 | 
			
		||||
        manage_taxonomies
 | 
			
		||||
        manage_invites
 | 
			
		||||
      ).freeze,
 | 
			
		||||
 | 
			
		||||
      administration: %w(
 | 
			
		||||
        manage_settings
 | 
			
		||||
        manage_rules
 | 
			
		||||
        manage_roles
 | 
			
		||||
        manage_webhooks
 | 
			
		||||
        manage_custom_emojis
 | 
			
		||||
        manage_announcements
 | 
			
		||||
      ).freeze,
 | 
			
		||||
 | 
			
		||||
      devops: %w(
 | 
			
		||||
        view_devops
 | 
			
		||||
      ).freeze,
 | 
			
		||||
 | 
			
		||||
      special: %i(
 | 
			
		||||
        administrator
 | 
			
		||||
      ).freeze,
 | 
			
		||||
    }.freeze
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  attr_writer :current_account
 | 
			
		||||
 | 
			
		||||
  validates :name, presence: true, unless: :everyone?
 | 
			
		||||
  validates :color, format: { with: /\A#?(?:[A-F0-9]{3}){1,2}\z/i }, unless: -> { color.blank? }
 | 
			
		||||
 | 
			
		||||
  validate :validate_permissions_elevation
 | 
			
		||||
  validate :validate_position_elevation
 | 
			
		||||
  validate :validate_dangerous_permissions
 | 
			
		||||
 | 
			
		||||
  before_validation :set_position
 | 
			
		||||
 | 
			
		||||
  scope :assignable, -> { where.not(id: -99).order(position: :asc) }
 | 
			
		||||
 | 
			
		||||
  has_many :users, inverse_of: :role, foreign_key: 'role_id', dependent: :nullify
 | 
			
		||||
 | 
			
		||||
  def self.nobody
 | 
			
		||||
    @nobody ||= UserRole.new(permissions: Flags::NONE, position: -1)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.everyone
 | 
			
		||||
    UserRole.find(-99)
 | 
			
		||||
  rescue ActiveRecord::RecordNotFound
 | 
			
		||||
    UserRole.create!(id: -99, permissions: Flags::DEFAULT)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def self.that_can(*any_of_privileges)
 | 
			
		||||
    all.select { |role| role.can?(*any_of_privileges) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def everyone?
 | 
			
		||||
    id == -99
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def nobody?
 | 
			
		||||
    id.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def permissions_as_keys
 | 
			
		||||
    FLAGS.keys.select { |privilege| permissions & FLAGS[privilege] == FLAGS[privilege] }.map(&:to_s)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def permissions_as_keys=(value)
 | 
			
		||||
    self.permissions = value.map(&:presence).compact.reduce(Flags::NONE) { |bitmask, privilege| FLAGS.key?(privilege.to_sym) ? (bitmask | FLAGS[privilege.to_sym]) : bitmask }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def can?(*any_of_privileges)
 | 
			
		||||
    any_of_privileges.any? { |privilege| in_permissions?(privilege) }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def overrides?(other_role)
 | 
			
		||||
    other_role.nil? || position > other_role.position
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def computed_permissions
 | 
			
		||||
    # If called on the everyone role, no further computation needed
 | 
			
		||||
    return permissions if everyone?
 | 
			
		||||
 | 
			
		||||
    # If called on the nobody role, no permissions are there to be given
 | 
			
		||||
    return Flags::NONE if nobody?
 | 
			
		||||
 | 
			
		||||
    # Otherwise, compute permissions based on special conditions
 | 
			
		||||
    @computed_permissions ||= begin
 | 
			
		||||
      permissions = self.class.everyone.permissions | self.permissions
 | 
			
		||||
 | 
			
		||||
      if permissions & FLAGS[:administrator] == FLAGS[:administrator]
 | 
			
		||||
        Flags::ALL
 | 
			
		||||
      else
 | 
			
		||||
        permissions
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def in_permissions?(privilege)
 | 
			
		||||
    raise ArgumentError, "Unknown privilege: #{privilege}" unless FLAGS.key?(privilege)
 | 
			
		||||
    computed_permissions & FLAGS[privilege] == FLAGS[privilege]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def set_position
 | 
			
		||||
    self.position = -1 if everyone?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_permissions_elevation
 | 
			
		||||
    errors.add(:permissions_as_keys, :elevated) if defined?(@current_account) && @current_account.user_role.computed_permissions & permissions != permissions
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_position_elevation
 | 
			
		||||
    errors.add(:position, :elevated) if defined?(@current_account) && @current_account.user_role.position < position
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def validate_dangerous_permissions
 | 
			
		||||
    errors.add(:permissions_as_keys, :dangerous) if everyone? && Flags::DEFAULT & permissions != permissions
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,11 +2,11 @@
 | 
			
		|||
 | 
			
		||||
class AccountModerationNotePolicy < ApplicationPolicy
 | 
			
		||||
  def create?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin? || owner?
 | 
			
		||||
    owner? || (role.can?(:manage_reports) && role.overrides?(record.account.user_role))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,74 +2,66 @@
 | 
			
		|||
 | 
			
		||||
class AccountPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def warn?
 | 
			
		||||
    staff? && !record.user&.staff?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def suspend?
 | 
			
		||||
    staff? && !record.user&.staff? && !record.instance_actor?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role) && !record.instance_actor?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    record.suspended_temporarily? && admin?
 | 
			
		||||
    record.suspended_temporarily? && role.can?(:delete_user_data)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsuspend?
 | 
			
		||||
    staff? && record.suspension_origin_local?
 | 
			
		||||
    role.can?(:manage_users) && record.suspension_origin_local?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def sensitive?
 | 
			
		||||
    staff? && !record.user&.staff?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsensitive?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def silence?
 | 
			
		||||
    staff? && !record.user&.staff?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsilence?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def redownload?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_avatar?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def remove_header?
 | 
			
		||||
    staff?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def subscribe?
 | 
			
		||||
    admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsubscribe?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_users, :manage_reports) && role.overrides?(record.user_role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def memorialize?
 | 
			
		||||
    admin? && !record.user&.admin? && !record.instance_actor?
 | 
			
		||||
    role.can?(:delete_user_data) && role.overrides?(record.user_role) && !record.instance_actor?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unblock_email?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def review?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
class AccountWarningPolicy < ApplicationPolicy
 | 
			
		||||
  def show?
 | 
			
		||||
    target? || staff?
 | 
			
		||||
    target? || role.can?(:manage_appeals)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def appeal?
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
class AccountWarningPresetPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
class AnnouncementPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_announcements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_announcements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_announcements)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_announcements)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,12 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class AppealPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_appeals)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def approve?
 | 
			
		||||
    record.pending? && staff?
 | 
			
		||||
    record.pending? && role.can?(:manage_appeals)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  alias reject? approve?
 | 
			
		||||
  def reject?
 | 
			
		||||
    record.pending? && role.can?(:manage_appeals)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,8 +8,6 @@ class ApplicationPolicy
 | 
			
		|||
    @record          = record
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  delegate :admin?, :moderator?, :staff?, to: :current_user, allow_nil: true
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def current_user
 | 
			
		||||
| 
						 | 
				
			
			@ -19,4 +17,8 @@ class ApplicationPolicy
 | 
			
		|||
  def user_signed_in?
 | 
			
		||||
    !current_user.nil?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    current_user&.role || UserRole.nobody
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								app/policies/audit_log_policy.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/policies/audit_log_policy.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class AuditLogPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    role.can?(:view_audit_log)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,30 +2,30 @@
 | 
			
		|||
 | 
			
		||||
class CustomEmojiPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def copy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_custom_emojis)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										7
									
								
								app/policies/dashboard_policy.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/policies/dashboard_policy.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class DashboardPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    role.can?(:view_dashboard)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class DeliveryPolicy < ApplicationPolicy
 | 
			
		||||
  def clear_delivery_errors?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def restart_delivery?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def stop_delivery?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
class DomainAllowPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,22 +2,22 @@
 | 
			
		|||
 | 
			
		||||
class DomainBlockPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class EmailDomainBlockPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class FollowRecommendationPolicy < ApplicationPolicy
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def suppress?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def unsuppress?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class InstancePolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,19 +2,19 @@
 | 
			
		|||
 | 
			
		||||
class InvitePolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_invites)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    min_required_role?
 | 
			
		||||
    role.can?(:invite_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def deactivate_all?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_invites)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    owner? || (Setting.min_invite_role == 'admin' ? admin? : staff?)
 | 
			
		||||
    owner? || role.can?(:manage_invites)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			@ -22,8 +22,4 @@ class InvitePolicy < ApplicationPolicy
 | 
			
		|||
  def owner?
 | 
			
		||||
    record.user_id == current_user&.id
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def min_required_role?
 | 
			
		||||
    current_user&.role?(Setting.min_invite_role)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class IpBlockPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_blocks)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,10 +2,10 @@
 | 
			
		|||
 | 
			
		||||
class PreviewCardPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def review?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,10 +2,10 @@
 | 
			
		|||
 | 
			
		||||
class PreviewCardProviderPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def review?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,6 +2,6 @@
 | 
			
		|||
 | 
			
		||||
class RelayPolicy < ApplicationPolicy
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_federation)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,11 +2,11 @@
 | 
			
		|||
 | 
			
		||||
class ReportNotePolicy < ApplicationPolicy
 | 
			
		||||
  def create?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin? || owner?
 | 
			
		||||
    owner? || (role.can?(:manage_reports) && role.overrides?(record.account.user_role))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class ReportPolicy < ApplicationPolicy
 | 
			
		||||
  def update?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
class RulePolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_rules)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_rules)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_rules)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_rules)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,14 +2,14 @@
 | 
			
		|||
 | 
			
		||||
class SettingsPolicy < ApplicationPolicy
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_settings)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,7 @@ class StatusPolicy < ApplicationPolicy
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_reports, :manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
| 
						 | 
				
			
			@ -32,17 +32,17 @@ class StatusPolicy < ApplicationPolicy
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    staff? || owned?
 | 
			
		||||
    role.can?(:manage_reports) || owned?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  alias unreblog? destroy?
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    staff? || owned?
 | 
			
		||||
    role.can?(:manage_reports) || owned?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def review?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,18 +2,18 @@
 | 
			
		|||
 | 
			
		||||
class TagPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def review?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_taxonomies)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,52 +2,38 @@
 | 
			
		|||
 | 
			
		||||
class UserPolicy < ApplicationPolicy
 | 
			
		||||
  def reset_password?
 | 
			
		||||
    staff? && !record.staff?
 | 
			
		||||
    role.can?(:manage_user_access) && role.overrides?(record.role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def change_email?
 | 
			
		||||
    staff? && !record.staff?
 | 
			
		||||
    role.can?(:manage_user_access) && role.overrides?(record.role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable_2fa?
 | 
			
		||||
    admin? && !record.staff?
 | 
			
		||||
    role.can?(:manage_user_access) && role.overrides?(record.role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def change_role?
 | 
			
		||||
    role.can?(:manage_roles) && role.overrides?(record.role)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def confirm?
 | 
			
		||||
    staff? && !record.confirmed?
 | 
			
		||||
    role.can?(:manage_user_access) && !record.confirmed?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable?
 | 
			
		||||
    staff?
 | 
			
		||||
    role.can?(:manage_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def approve?
 | 
			
		||||
    staff? && !record.approved?
 | 
			
		||||
    role.can?(:manage_users) && !record.approved?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def reject?
 | 
			
		||||
    staff? && !record.approved?
 | 
			
		||||
    role.can?(:manage_users) && !record.approved?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable?
 | 
			
		||||
    staff? && !record.admin?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def promote?
 | 
			
		||||
    admin? && promotable?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def demote?
 | 
			
		||||
    admin? && !record.admin? && demoteable?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def promotable?
 | 
			
		||||
    record.approved? && (!record.staff? || !record.admin?)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def demoteable?
 | 
			
		||||
    record.staff?
 | 
			
		||||
    role.can?(:manage_users) && role.overrides?(record.role)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								app/policies/user_role_policy.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								app/policies/user_role_policy.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,19 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class UserRolePolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    role.can?(:manage_roles)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    role.can?(:manage_roles)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    role.can?(:manage_roles) && role.overrides?(record)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    !record.everyone? && role.can?(:manage_roles) && role.overrides?(record) && role.id != record.id
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -2,34 +2,34 @@
 | 
			
		|||
 | 
			
		||||
class WebhookPolicy < ApplicationPolicy
 | 
			
		||||
  def index?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def show?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def update?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def enable?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def disable?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def rotate_secret?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def destroy?
 | 
			
		||||
    admin?
 | 
			
		||||
    role.can?(:manage_webhooks)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,4 +3,8 @@
 | 
			
		|||
class InitialStatePresenter < ActiveModelSerializers::Model
 | 
			
		||||
  attributes :settings, :push_subscription, :token,
 | 
			
		||||
             :current_account, :admin, :text, :visibility
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    current_account&.user_role
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ class InitialStateSerializer < ActiveModel::Serializer
 | 
			
		|||
             :languages
 | 
			
		||||
 | 
			
		||||
  has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer
 | 
			
		||||
  has_one :role, serializer: REST::RoleSerializer
 | 
			
		||||
 | 
			
		||||
  def meta
 | 
			
		||||
    store = {
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,6 @@ class InitialStateSerializer < ActiveModel::Serializer
 | 
			
		|||
      repository: Mastodon::Version.repository,
 | 
			
		||||
      source_url: Mastodon::Version.source_url,
 | 
			
		||||
      version: Mastodon::Version.to_s,
 | 
			
		||||
      invites_enabled: Setting.min_invite_role == 'user',
 | 
			
		||||
      limited_federation_mode: Rails.configuration.x.whitelist_mode,
 | 
			
		||||
      mascot: instance_presenter.mascot&.file&.url,
 | 
			
		||||
      profile_directory: Setting.profile_directory,
 | 
			
		||||
| 
						 | 
				
			
			@ -39,7 +39,6 @@ class InitialStateSerializer < ActiveModel::Serializer
 | 
			
		|||
      store[:advanced_layout]   = object.current_account.user.setting_advanced_layout
 | 
			
		||||
      store[:use_blurhash]      = object.current_account.user.setting_use_blurhash
 | 
			
		||||
      store[:use_pending_items] = object.current_account.user.setting_use_pending_items
 | 
			
		||||
      store[:is_staff]          = object.current_account.user.staff?
 | 
			
		||||
      store[:trends]            = Setting.trends && object.current_account.user.setting_trends
 | 
			
		||||
      store[:crop_images]       = object.current_account.user.setting_crop_images
 | 
			
		||||
    else
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@
 | 
			
		|||
class REST::CredentialAccountSerializer < REST::AccountSerializer
 | 
			
		||||
  attributes :source
 | 
			
		||||
 | 
			
		||||
  has_one :role, serializer: REST::RoleSerializer
 | 
			
		||||
 | 
			
		||||
  def source
 | 
			
		||||
    user = object.user
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -15,4 +17,8 @@ class REST::CredentialAccountSerializer < REST::AccountSerializer
 | 
			
		|||
      follow_requests_count: FollowRequest.where(target_account: object).limit(40).count,
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def role
 | 
			
		||||
    object.user_role
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -93,7 +93,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def invites_enabled
 | 
			
		||||
    Setting.min_invite_role == 'user'
 | 
			
		||||
    UserRole.everyone.can?(:invite_users)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								app/serializers/rest/role_serializer.rb
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/serializers/rest/role_serializer.rb
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
# frozen_string_literal: true
 | 
			
		||||
 | 
			
		||||
class REST::RoleSerializer < ActiveModel::Serializer
 | 
			
		||||
  attributes :id, :name, :permissions, :color, :highlighted
 | 
			
		||||
 | 
			
		||||
  def id
 | 
			
		||||
    object.id.to_s
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def permissions
 | 
			
		||||
    object.computed_permissions.to_s
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			@ -61,11 +61,11 @@ class AccountSearchService < BaseService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def advanced_search_results
 | 
			
		||||
    Account.advanced_search_for(terms_for_query, account, limit_for_non_exact_results, options[:following], offset)
 | 
			
		||||
    Account.advanced_search_for(terms_for_query, account, limit: limit_for_non_exact_results, following: options[:following], offset: offset)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def simple_search_results
 | 
			
		||||
    Account.search_for(terms_for_query, limit_for_non_exact_results, offset)
 | 
			
		||||
    Account.search_for(terms_for_query, limit: limit_for_non_exact_results, offset: offset)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def from_elasticsearch
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ class AppealService < BaseService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def notify_staff!
 | 
			
		||||
    User.staff.includes(:account).each do |u|
 | 
			
		||||
    User.those_who_can(:manage_appeals).includes(:account).each do |u|
 | 
			
		||||
      AdminMailer.new_appeal(u.account, @appeal).deliver_later if u.allows_appeal_emails?
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ class BootstrapTimelineService < BaseService
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def notify_staff!
 | 
			
		||||
    User.staff.includes(:account).find_each do |user|
 | 
			
		||||
    User.those_who_can(:manage_users).includes(:account).find_each do |user|
 | 
			
		||||
      LocalNotificationWorker.perform_async(user.account_id, @source_account.id, 'Account', 'admin.sign_up')
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Reference in a new issue