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
|
@ -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
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -76,7 +76,7 @@ class NotifyService < BaseService
|
|||
end
|
||||
|
||||
def from_staff?
|
||||
@notification.from_account.local? && @notification.from_account.user.present? && @notification.from_account.user.staff?
|
||||
@notification.from_account.local? && @notification.from_account.user.present? && @notification.from_account.user_role&.overrides?(@recipient.user_role)
|
||||
end
|
||||
|
||||
def optional_non_following_and_direct?
|
||||
|
|
|
@ -38,7 +38,7 @@ class ReportService < BaseService
|
|||
def notify_staff!
|
||||
return if @report.unresolved_siblings?
|
||||
|
||||
User.staff.includes(:account).each do |u|
|
||||
User.those_who_can(:manage_reports).includes(:account).each do |u|
|
||||
LocalNotificationWorker.perform_async(u.account_id, @report.id, 'Report', 'admin.report')
|
||||
AdminMailer.new_report(u.account, @report).deliver_later if u.allows_report_emails?
|
||||
end
|
||||
|
|
|
@ -4,45 +4,36 @@
|
|||
- content_for :header_tags do
|
||||
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
|
||||
|
||||
.filters
|
||||
.filter-subset
|
||||
%strong= t('admin.accounts.location.title')
|
||||
%ul
|
||||
%li= filter_link_to t('generic.all'), origin: nil
|
||||
%li= filter_link_to t('admin.accounts.location.local'), origin: 'local'
|
||||
%li= filter_link_to t('admin.accounts.location.remote'), origin: 'remote'
|
||||
.filter-subset
|
||||
%strong= t('admin.accounts.moderation.title')
|
||||
%ul
|
||||
%li= filter_link_to t('generic.all'), status: nil
|
||||
%li= filter_link_to t('admin.accounts.moderation.active'), status: 'active'
|
||||
%li= filter_link_to t('admin.accounts.moderation.suspended'), status: 'suspended'
|
||||
%li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{number_with_delimiter(User.pending.count)})"], ' '), status: 'pending'
|
||||
.filter-subset
|
||||
%strong= t('admin.accounts.role')
|
||||
%ul
|
||||
%li= filter_link_to t('admin.accounts.moderation.all'), permissions: nil
|
||||
%li= filter_link_to t('admin.accounts.roles.staff'), permissions: 'staff'
|
||||
.filter-subset
|
||||
%strong= t 'generic.order_by'
|
||||
%ul
|
||||
%li= filter_link_to t('relationships.most_recent'), order: nil
|
||||
%li= filter_link_to t('relationships.last_active'), order: 'active'
|
||||
|
||||
= form_tag admin_accounts_url, method: 'GET', class: 'simple_form' do
|
||||
.fields-group
|
||||
- (AccountFilter::KEYS - %i(origin status permissions)).each do |key|
|
||||
- if params[key].present?
|
||||
= hidden_field_tag key, params[key]
|
||||
.filters
|
||||
.filter-subset.filter-subset--with-select
|
||||
%strong= t('admin.accounts.location.title')
|
||||
.input.select.optional
|
||||
= select_tag :origin, options_for_select([[t('admin.accounts.location.local'), 'local'], [t('admin.accounts.location.remote'), 'remote']], params[:origin]), prompt: I18n.t('generic.all')
|
||||
.filter-subset.filter-subset--with-select
|
||||
%strong= t('admin.accounts.moderation.title')
|
||||
.input.select.optional
|
||||
= select_tag :status, options_for_select([[t('admin.accounts.moderation.active'), 'active'], [t('admin.accounts.moderation.silenced'), 'silenced'], [t('admin.accounts.moderation.suspended'), 'suspended'], [safe_join([t('admin.accounts.moderation.pending'), "(#{number_with_delimiter(User.pending.count)})"], ' '), 'pending']], params[:status]), prompt: I18n.t('generic.all')
|
||||
.filter-subset.filter-subset--with-select
|
||||
%strong= t('admin.accounts.role')
|
||||
.input.select.optional
|
||||
= select_tag :role_ids, options_from_collection_for_select(UserRole.assignable, :id, :name, params[:role_ids]), prompt: I18n.t('admin.accounts.moderation.all')
|
||||
.filter-subset.filter-subset--with-select
|
||||
%strong= t 'generic.order_by'
|
||||
.input.select
|
||||
= select_tag :order, options_for_select([[t('relationships.most_recent'), nil], [t('relationships.last_active'), 'active']], params[:order])
|
||||
|
||||
.fields-group
|
||||
- %i(username by_domain display_name email ip).each do |key|
|
||||
- unless key == :by_domain && params[:origin] != 'remote'
|
||||
.input.string.optional
|
||||
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.accounts.#{key}")
|
||||
|
||||
.actions
|
||||
%button.button= t('admin.accounts.search')
|
||||
= link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'
|
||||
.actions
|
||||
%button.button= t('admin.accounts.search')
|
||||
= link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
= form_for(@form, url: batch_admin_accounts_path) do |f|
|
||||
= hidden_field_tag :page, params[:page] || 1
|
||||
|
|
|
@ -92,10 +92,13 @@
|
|||
|
||||
%tr
|
||||
%th= t('admin.accounts.role')
|
||||
%td= t("admin.accounts.roles.#{@account.user&.role}")
|
||||
%td
|
||||
= table_link_to 'angle-double-up', t('admin.accounts.promote'), promote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:promote, @account.user)
|
||||
= table_link_to 'angle-double-down', t('admin.accounts.demote'), demote_admin_account_role_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:demote, @account.user)
|
||||
- if @account.user_role&.everyone?
|
||||
= t('admin.accounts.no_role_assigned')
|
||||
- else
|
||||
= @account.user_role&.name
|
||||
%td
|
||||
= table_link_to 'vcard', t('admin.accounts.change_role.label'), admin_user_role_path(@account.user) if can?(:change_role, @account.user)
|
||||
|
||||
%tr
|
||||
%th{ rowspan: can?(:create, :email_domain_block) ? 3 : 2 }= t('admin.accounts.email')
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
.filter-subset.filter-subset--with-select
|
||||
%strong= t('admin.action_logs.filter_by_user')
|
||||
.input.select.optional
|
||||
= select_tag :account_id, options_from_collection_for_select(Account.joins(:user).merge(User.staff), :id, :username, params[:account_id]), prompt: I18n.t('admin.accounts.moderation.all')
|
||||
= select_tag :account_id, options_from_collection_for_select(@auditable_accounts, :id, :username, params[:account_id]), prompt: I18n.t('admin.accounts.moderation.all')
|
||||
|
||||
.filter-subset.filter-subset--with-select
|
||||
%strong= t('admin.action_logs.filter_by_action')
|
||||
|
|
|
@ -4,32 +4,33 @@
|
|||
- content_for :header_tags do
|
||||
= javascript_pack_tag 'admin', async: true, crossorigin: 'anonymous'
|
||||
|
||||
- content_for :heading_actions do
|
||||
= l(@time_period.first)
|
||||
= ' - '
|
||||
= l(@time_period.last)
|
||||
- if current_user.can?(:view_dashboard)
|
||||
- content_for :heading_actions do
|
||||
= l(@time_period.first)
|
||||
= ' - '
|
||||
= l(@time_period.last)
|
||||
|
||||
%p
|
||||
= fa_icon 'info fw'
|
||||
= t('admin.instances.totals_time_period_hint_html')
|
||||
%p
|
||||
= fa_icon 'info fw'
|
||||
= t('admin.instances.totals_time_period_hint_html')
|
||||
|
||||
.dashboard
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
|
||||
.dashboard
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_accounts_measure'), href: admin_accounts_path(origin: 'remote', by_domain: @instance.domain)
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_statuses', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_statuses_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_media_attachments', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_media_attachments_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_follows', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_follows_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_followers', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_followers_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'instance_reports', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, label: t('admin.instances.dashboard.instance_reports_measure'), href: admin_reports_path(by_target_domain: @instance.domain)
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'instance_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_accounts_dimension')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'instance_languages', start_at: @time_period.first, end_at: @time_period.last, params: { domain: @instance.domain }, limit: 8, label: t('admin.instances.dashboard.instance_languages_dimension')
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
= simple_form_for @role, url: @role.new_record? ? admin_roles_path : admin_role_path(@role) do |f|
|
||||
= render 'shared/error_messages', object: @role
|
||||
|
||||
- if @role.everyone?
|
||||
.flash-message.info
|
||||
= t('admin.roles.everyone_full_description_html')
|
||||
- else
|
||||
.fields-group
|
||||
= f.input :name, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :position, wrapper: :with_label
|
||||
|
||||
.fields-group
|
||||
= f.input :color, wrapper: :with_label, input_html: { placeholder: '#000000' }
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
.fields-group
|
||||
= f.input :highlighted, wrapper: :with_label
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
.field-group
|
||||
.input.with_block_label
|
||||
%label= t('simple_form.labels.user_role.permissions_as_keys')
|
||||
%span.hint= t('simple_form.hints.user_role.permissions_as_keys')
|
||||
|
||||
- (@role.everyone? ? UserRole::Flags::CATEGORIES.slice(:invites) : UserRole::Flags::CATEGORIES).each do |category, permissions|
|
||||
%h4= t(category, scope: 'admin.roles.categories')
|
||||
|
||||
= f.input :permissions_as_keys, collection: permissions, wrapper: :with_block_label, include_blank: false, label_method: lambda { |privilege| safe_join([t("admin.roles.privileges.#{privilege}"), content_tag(:span, t("admin.roles.privileges.#{privilege}_description"), class: 'hint')]) }, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li', label: false, hint: false
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
.actions
|
||||
= f.button :button, @role.new_record? ? t('admin.roles.add_new') : t('generic.save_changes'), type: :submit
|
|
@ -0,0 +1,18 @@
|
|||
.announcements-list__item
|
||||
= link_to edit_admin_role_path(role), class: 'announcements-list__item__title' do
|
||||
%span.user-role{ class: "user-role-#{role.id}" }
|
||||
= fa_icon 'users fw'
|
||||
|
||||
- if role.everyone?
|
||||
= t('admin.roles.everyone')
|
||||
- else
|
||||
= role.name
|
||||
|
||||
.announcements-list__item__action-bar
|
||||
.announcements-list__item__meta
|
||||
- if role.everyone?
|
||||
= t('admin.roles.everyone_full_description_html')
|
||||
- else
|
||||
= link_to t('admin.roles.assigned_users', count: role.users.count), admin_accounts_path(role_id: role.id)
|
||||
•
|
||||
%abbr{ title: role.permissions_as_keys.map { |privilege| I18n.t("admin.roles.privileges.#{privilege}") }.join(', ') }= t('admin.roles.permissions_count', count: role.permissions_as_keys.size)
|
|
@ -0,0 +1,8 @@
|
|||
- content_for :page_title do
|
||||
= t('admin.roles.edit', name: @role.everyone? ? t('admin.roles.everyone') : @role.name)
|
||||
|
||||
- content_for :heading_actions do
|
||||
= link_to t('admin.roles.delete'), admin_role_path(@role), method: :delete, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' if can?(:destroy, @role)
|
||||
|
||||
= render partial: 'form'
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
- content_for :page_title do
|
||||
= t('admin.roles.title')
|
||||
|
||||
- content_for :heading_actions do
|
||||
= link_to t('admin.roles.add_new'), new_admin_role_path, class: 'button' if can?(:create, :user_role)
|
||||
|
||||
%p= t('admin.roles.description_html')
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
.applications-list
|
||||
= render partial: 'role', collection: @roles.select(&:everyone?)
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
.applications-list
|
||||
= render partial: 'role', collection: @roles.reject(&:everyone?)
|
|
@ -0,0 +1,4 @@
|
|||
- content_for :page_title do
|
||||
= t('admin.roles.add_new')
|
||||
|
||||
= render partial: 'form'
|
|
@ -61,9 +61,6 @@
|
|||
.fields-group
|
||||
= f.input :show_known_fediverse_at_about_page, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_known_fediverse_at_about_page.title'), hint: t('admin.settings.show_known_fediverse_at_about_page.desc_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :show_staff_badge, as: :boolean, wrapper: :with_label, label: t('admin.settings.show_staff_badge.title'), hint: t('admin.settings.show_staff_badge.desc_html')
|
||||
|
||||
.fields-group
|
||||
= f.input :open_deletion, as: :boolean, wrapper: :with_label, label: t('admin.settings.registrations.deletion.title'), hint: t('admin.settings.registrations.deletion.desc_html')
|
||||
|
||||
|
@ -91,9 +88,6 @@
|
|||
|
||||
%hr.spacer/
|
||||
|
||||
.fields-group
|
||||
= f.input :min_invite_role, wrapper: :with_label, collection: %i(disabled user moderator admin), label: t('admin.settings.registrations.min_invite_role.title'), label_method: lambda { |role| role == :disabled ? t('admin.settings.registrations.min_invite_role.disabled') : t("admin.accounts.roles.#{role}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
|
||||
.fields-row
|
||||
.fields-row__column.fields-row__column-6.fields-group
|
||||
= f.input :show_domain_blocks, wrapper: :with_label, collection: %i(disabled users all), label: t('admin.settings.domain_blocks.title'), label_method: lambda { |value| t("admin.settings.domain_blocks.#{value}") }, include_blank: false, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li'
|
||||
|
|
|
@ -4,49 +4,50 @@
|
|||
- content_for :page_title do
|
||||
= "##{@tag.name}"
|
||||
|
||||
- content_for :heading_actions do
|
||||
= l(@time_period.first)
|
||||
= ' - '
|
||||
= l(@time_period.last)
|
||||
- if current_user.can?(:view_dashboard)
|
||||
- content_for :heading_actions do
|
||||
= l(@time_period.first)
|
||||
= ' - '
|
||||
= l(@time_period.last)
|
||||
|
||||
.dashboard
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure'), href: tag_url(@tag), target: '_blank'
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_uses', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_uses_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_servers', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_servers_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'tag_servers', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, limit: 8, label: t('admin.trends.tags.dashboard.tag_servers_dimension')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'tag_languages', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, limit: 8, label: t('admin.trends.tags.dashboard.tag_languages_dimension')
|
||||
.dashboard__item
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.usable? ? 'positive' : 'negative'] do
|
||||
- if @tag.usable?
|
||||
%span= t('admin.trends.tags.usable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_usable')
|
||||
= fa_icon 'lock fw'
|
||||
.dashboard
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_accounts', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_accounts_measure'), href: tag_url(@tag), target: '_blank'
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_uses', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_uses_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :counter, measure: 'tag_servers', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, label: t('admin.trends.tags.dashboard.tag_servers_measure')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'tag_servers', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, limit: 8, label: t('admin.trends.tags.dashboard.tag_servers_dimension')
|
||||
.dashboard__item
|
||||
= react_admin_component :dimension, dimension: 'tag_languages', start_at: @time_period.first, end_at: @time_period.last, params: { id: @tag.id }, limit: 8, label: t('admin.trends.tags.dashboard.tag_languages_dimension')
|
||||
.dashboard__item
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.usable? ? 'positive' : 'negative'] do
|
||||
- if @tag.usable?
|
||||
%span= t('admin.trends.tags.usable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_usable')
|
||||
= fa_icon 'lock fw'
|
||||
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.trendable? ? 'positive' : 'negative'] do
|
||||
- if @tag.trendable?
|
||||
%span= t('admin.trends.tags.trendable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_trendable')
|
||||
= fa_icon 'lock fw'
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.trendable? ? 'positive' : 'negative'] do
|
||||
- if @tag.trendable?
|
||||
%span= t('admin.trends.tags.trendable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_trendable')
|
||||
= fa_icon 'lock fw'
|
||||
|
||||
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
|
||||
- if @tag.listable?
|
||||
%span= t('admin.trends.tags.listable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_listable')
|
||||
= fa_icon 'lock fw'
|
||||
= link_to admin_tag_path(@tag.id), class: ['dashboard__quick-access', @tag.listable? ? 'positive' : 'negative'] do
|
||||
- if @tag.listable?
|
||||
%span= t('admin.trends.tags.listable')
|
||||
= fa_icon 'check fw'
|
||||
- else
|
||||
%span= t('admin.trends.tags.not_listable')
|
||||
= fa_icon 'lock fw'
|
||||
|
||||
%hr.spacer/
|
||||
%hr.spacer/
|
||||
|
||||
= simple_form_for @tag, url: admin_tag_path(@tag.id) do |f|
|
||||
= render 'shared/error_messages', object: @tag
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
- content_for :page_title do
|
||||
= t('admin.accounts.change_role.title', username: @user.account.username)
|
||||
|
||||
= simple_form_for @user, url: admin_user_role_path(@user) do |f|
|
||||
.fields-group
|
||||
= f.association :role, wrapper: :with_block_label, collection: UserRole.assignable, label_method: :name, include_blank: I18n.t('admin.accounts.change_role.no_role')
|
||||
|
||||
.actions
|
||||
= f.button :button, t('generic.save_changes'), type: :submit
|
|
@ -0,0 +1,10 @@
|
|||
<%- if Setting.custom_css.present? %>
|
||||
<%= Setting.custom_css %>
|
||||
|
||||
<%- end %>
|
||||
<%- UserRole.where(highlighted: true).select { |role| role.color.present? }.each do |role| %>
|
||||
.user-role-<%= role.id %> {
|
||||
--user-role-accent: <%= role.color %>;
|
||||
}
|
||||
|
||||
<%- end %>
|
|
@ -34,9 +34,7 @@
|
|||
%meta{ name: 'style-nonce', content: request.content_security_policy_nonce }
|
||||
|
||||
= stylesheet_link_tag '/inert.css', skip_pipeline: true, media: 'all', id: 'inert-style'
|
||||
|
||||
- if Setting.custom_css.present?
|
||||
= stylesheet_link_tag custom_css_path, host: request.host, media: 'all'
|
||||
= stylesheet_link_tag custom_css_path, host: default_url_options[:host], media: 'all'
|
||||
|
||||
= yield :header_tags
|
||||
|
||||
|
|
|
@ -18,12 +18,10 @@
|
|||
= ff.input :reblog, as: :boolean, wrapper: :with_label
|
||||
= ff.input :favourite, as: :boolean, wrapper: :with_label
|
||||
= ff.input :mention, as: :boolean, wrapper: :with_label
|
||||
|
||||
- if current_user.staff?
|
||||
= ff.input :report, as: :boolean, wrapper: :with_label
|
||||
= ff.input :appeal, as: :boolean, wrapper: :with_label
|
||||
= ff.input :pending_account, as: :boolean, wrapper: :with_label
|
||||
= ff.input :trending_tag, as: :boolean, wrapper: :with_label
|
||||
= ff.input :report, as: :boolean, wrapper: :with_label if current_user.can?(:manage_reports)
|
||||
= ff.input :appeal, as: :boolean, wrapper: :with_label if current_user.can?(:manage_appeals)
|
||||
= ff.input :pending_account, as: :boolean, wrapper: :with_label if current_user.can?(:manage_users)
|
||||
= ff.input :trending_tag, as: :boolean, wrapper: :with_label if current_user.can?(:manage_taxonomies)
|
||||
|
||||
.fields-group
|
||||
= f.input :setting_always_send_emails, as: :boolean, wrapper: :with_label
|
||||
|
|
|
@ -44,6 +44,7 @@ require_relative '../lib/webpacker/helper_extensions'
|
|||
require_relative '../lib/rails/engine_extensions'
|
||||
require_relative '../lib/active_record/database_tasks_extensions'
|
||||
require_relative '../lib/active_record/batches'
|
||||
require_relative '../lib/simple_navigation/item_extensions'
|
||||
|
||||
Dotenv::Railtie.load
|
||||
|
||||
|
|
|
@ -38,3 +38,12 @@ en:
|
|||
email:
|
||||
blocked: uses a disallowed e-mail provider
|
||||
unreachable: does not seem to exist
|
||||
role_id:
|
||||
elevated: cannot be higher than your current role
|
||||
user_role:
|
||||
attributes:
|
||||
permissions_as_keys:
|
||||
dangerous: include permissions that are not safe for the base role
|
||||
elevated: cannot include permissions your current role does not possess
|
||||
position:
|
||||
elevated: cannot be higher than your current role
|
||||
|
|
|
@ -83,10 +83,8 @@ en:
|
|||
posts_tab_heading: Posts
|
||||
posts_with_replies: Posts and replies
|
||||
roles:
|
||||
admin: Admin
|
||||
bot: Bot
|
||||
group: Group
|
||||
moderator: Mod
|
||||
unavailable: Profile unavailable
|
||||
unfollow: Unfollow
|
||||
admin:
|
||||
|
@ -105,12 +103,17 @@ en:
|
|||
avatar: Avatar
|
||||
by_domain: Domain
|
||||
change_email:
|
||||
changed_msg: Account email successfully changed!
|
||||
changed_msg: Email successfully changed!
|
||||
current_email: Current email
|
||||
label: Change email
|
||||
new_email: New email
|
||||
submit: Change email
|
||||
title: Change email for %{username}
|
||||
change_role:
|
||||
changed_msg: Role successfully changed!
|
||||
label: Change role
|
||||
no_role: No role
|
||||
title: Change role for %{username}
|
||||
confirm: Confirm
|
||||
confirmed: Confirmed
|
||||
confirming: Confirming
|
||||
|
@ -154,6 +157,7 @@ en:
|
|||
active: Active
|
||||
all: All
|
||||
pending: Pending
|
||||
silenced: Limited
|
||||
suspended: Suspended
|
||||
title: Moderation
|
||||
moderation_notes: Moderation notes
|
||||
|
@ -161,6 +165,7 @@ en:
|
|||
most_recent_ip: Most recent IP
|
||||
no_account_selected: No accounts were changed as none were selected
|
||||
no_limits_imposed: No limits imposed
|
||||
no_role_assigned: No role assigned
|
||||
not_subscribed: Not subscribed
|
||||
pending: Pending review
|
||||
perform_full_suspension: Suspend
|
||||
|
@ -187,12 +192,7 @@ en:
|
|||
reset: Reset
|
||||
reset_password: Reset password
|
||||
resubscribe: Resubscribe
|
||||
role: Permissions
|
||||
roles:
|
||||
admin: Administrator
|
||||
moderator: Moderator
|
||||
staff: Staff
|
||||
user: User
|
||||
role: Role
|
||||
search: Search
|
||||
search_same_email_domain: Other users with the same e-mail domain
|
||||
search_same_ip: Other users with the same IP
|
||||
|
@ -649,6 +649,67 @@ en:
|
|||
unresolved: Unresolved
|
||||
updated_at: Updated
|
||||
view_profile: View profile
|
||||
roles:
|
||||
add_new: Add role
|
||||
assigned_users:
|
||||
one: "%{count} user"
|
||||
other: "%{count} users"
|
||||
categories:
|
||||
administration: Administration
|
||||
devops: Devops
|
||||
invites: Invites
|
||||
moderation: Moderation
|
||||
special: Special
|
||||
delete: Delete
|
||||
description_html: With <strong>user roles</strong>, you can customize which functions and areas of Mastodon your users can access.
|
||||
edit: Edit '%{name}' role
|
||||
everyone: Default permissions
|
||||
everyone_full_description_html: This is the <strong>base role</strong> affecting <strong>all users</strong>, even those without an assigned role. All other roles inherit permissions from it.
|
||||
permissions_count:
|
||||
one: "%{count} permission"
|
||||
other: "%{count} permissions"
|
||||
privileges:
|
||||
administrator: Administrator
|
||||
administrator_description: Users with this permission will bypass every permission
|
||||
delete_user_data: Delete User Data
|
||||
delete_user_data_description: Allows users to delete other users' data without delay
|
||||
invite_users: Invite Users
|
||||
invite_users_description: Allows users to invite new people to the server
|
||||
manage_announcements: Manage Announcements
|
||||
manage_announcements_description: Allows users to manage announcements on the server
|
||||
manage_appeals: Manage Appeals
|
||||
manage_appeals_description: Allows users to review appeals against moderation actions
|
||||
manage_blocks: Manage Blocks
|
||||
manage_blocks_description: Allows users to block e-mail providers and IP addresses
|
||||
manage_custom_emojis: Manage Custom Emojis
|
||||
manage_custom_emojis_description: Allows users to manage custom emojis on the server
|
||||
manage_federation: Manage Federation
|
||||
manage_federation_description: Allows users to block or allow federation with other domains, and control deliverability
|
||||
manage_invites: Manage Invites
|
||||
manage_invites_description: Allows users to browse and deactivate invite links
|
||||
manage_reports: Manage Reports
|
||||
manage_reports_description: Allows users to review reports and perform moderation actions against them
|
||||
manage_roles: Manage Roles
|
||||
manage_roles_description: Allows users to manage and assign roles below theirs
|
||||
manage_rules: Manage Rules
|
||||
manage_rules_description: Allows users to change server rules
|
||||
manage_settings: Manage Settings
|
||||
manage_settings_description: Allows users to change site settings
|
||||
manage_taxonomies: Manage Taxonomies
|
||||
manage_taxonomies_description: Allows users to review trending content and update hashtag settings
|
||||
manage_user_access: Manage User Access
|
||||
manage_user_access_description: Allows users to disable other users' two-factor authentication, change their e-mail address, and reset their password
|
||||
manage_users: Manage Users
|
||||
manage_users_description: Allows users to view other users' details and perform moderation actions against them
|
||||
manage_webhooks: Manage Webhooks
|
||||
manage_webhooks_description: Allows users to set up webhooks for administrative events
|
||||
view_audit_log: View Audit Log
|
||||
view_audit_log_description: Allows users to see a history of administrative actions on the server
|
||||
view_dashboard: View Dashboard
|
||||
view_dashboard_description: Allows users to access the dashboard and various metrics
|
||||
view_devops: Devops
|
||||
view_devops_description: Allows users to access Sidekiq and pgHero dashboards
|
||||
title: Roles
|
||||
rules:
|
||||
add_new: Add rule
|
||||
delete: Delete
|
||||
|
@ -701,9 +762,6 @@ en:
|
|||
deletion:
|
||||
desc_html: Allow anyone to delete their account
|
||||
title: Open account deletion
|
||||
min_invite_role:
|
||||
disabled: No one
|
||||
title: Allow invitations by
|
||||
require_invite_text:
|
||||
desc_html: When registrations require manual approval, make the “Why do you want to join?” text input mandatory rather than optional
|
||||
title: Require new users to enter a reason to join
|
||||
|
@ -716,9 +774,6 @@ en:
|
|||
show_known_fediverse_at_about_page:
|
||||
desc_html: When disabled, restricts the public timeline linked from the landing page to showing only local content
|
||||
title: Include federated content on unauthenticated public timeline page
|
||||
show_staff_badge:
|
||||
desc_html: Show a staff badge on a user page
|
||||
title: Show staff badge
|
||||
site_description:
|
||||
desc_html: Introductory paragraph on the API. Describe what makes this Mastodon server special and anything else important. You can use HTML tags, in particular <code><a></code> and <code><em></code>.
|
||||
title: Server description
|
||||
|
|
|
@ -96,6 +96,13 @@ en:
|
|||
name: You can only change the casing of the letters, for example, to make it more readable
|
||||
user:
|
||||
chosen_languages: When checked, only posts in selected languages will be displayed in public timelines
|
||||
role: The role controls which permissions the user has
|
||||
user_role:
|
||||
color: Color to be used for the role throughout the UI, as RGB in hex format
|
||||
highlighted: This makes the role publicly visible
|
||||
name: Public name of the role, if role is set to be displayed as a badge
|
||||
permissions_as_keys: Users with this role will have access to...
|
||||
position: Higher role decides conflict resolution in certain situations
|
||||
webhook:
|
||||
events: Select events to send
|
||||
url: Where events will be sent to
|
||||
|
@ -232,6 +239,14 @@ en:
|
|||
name: Hashtag
|
||||
trendable: Allow this hashtag to appear under trends
|
||||
usable: Allow posts to use this hashtag
|
||||
user:
|
||||
role: Role
|
||||
user_role:
|
||||
color: Badge color
|
||||
highlighted: Display role as badge on user profiles
|
||||
name: Name
|
||||
permissions_as_keys: Permissions
|
||||
position: Priority
|
||||
webhook:
|
||||
events: Enabled events
|
||||
url: Endpoint URL
|
||||
|
|
|
@ -2,66 +2,67 @@
|
|||
|
||||
SimpleNavigation::Configuration.run do |navigation|
|
||||
navigation.items do |n|
|
||||
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_url
|
||||
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path
|
||||
|
||||
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_url, if: -> { current_user.functional? } do |s|
|
||||
s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_url
|
||||
s.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_url
|
||||
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? } do |s|
|
||||
s.item :profile, safe_join([fa_icon('pencil fw'), t('settings.appearance')]), settings_profile_path
|
||||
s.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_path
|
||||
end
|
||||
|
||||
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_url, if: -> { current_user.functional? } do |s|
|
||||
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_url
|
||||
s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_url
|
||||
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_url
|
||||
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? } do |s|
|
||||
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_path
|
||||
s.item :notifications, safe_join([fa_icon('bell fw'), t('settings.notifications')]), settings_preferences_notifications_path
|
||||
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path
|
||||
end
|
||||
|
||||
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_url, if: -> { current_user.functional? }
|
||||
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? }
|
||||
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? }
|
||||
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_url, if: -> { current_user.functional? }
|
||||
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional? }
|
||||
|
||||
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_url do |s|
|
||||
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_url, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
|
||||
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_url, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
|
||||
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_url
|
||||
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s|
|
||||
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
|
||||
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
|
||||
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path
|
||||
end
|
||||
|
||||
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_url do |s|
|
||||
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_url, if: -> { current_user.functional? }
|
||||
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_url
|
||||
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_path do |s|
|
||||
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_import_path, if: -> { current_user.functional? }
|
||||
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path
|
||||
end
|
||||
|
||||
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: proc { Setting.min_invite_role == 'user' && current_user.functional? }
|
||||
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_url, if: -> { current_user.functional? }
|
||||
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? }
|
||||
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, if: -> { current_user.functional? }
|
||||
|
||||
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_tags_path, if: proc { current_user.staff? } do |s|
|
||||
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) } do |s|
|
||||
s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
|
||||
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/tags|/admin/trends/tags}
|
||||
s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
|
||||
end
|
||||
|
||||
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |s|
|
||||
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url
|
||||
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports}
|
||||
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes}
|
||||
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path
|
||||
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}
|
||||
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: whitelist_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.admin? }
|
||||
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_url, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.admin? }
|
||||
s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_url, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.admin? }
|
||||
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) } do |s|
|
||||
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports}, if: -> { current_user.can?(:manage_reports) }
|
||||
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
|
||||
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
|
||||
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) }
|
||||
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: whitelist_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) }
|
||||
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) }
|
||||
s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) }
|
||||
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }
|
||||
end
|
||||
|
||||
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_dashboard_url, if: proc { current_user.staff? } do |s|
|
||||
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_url
|
||||
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}
|
||||
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}
|
||||
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}
|
||||
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
|
||||
s.item :webhooks, safe_join([fa_icon('inbox fw'), t('admin.webhooks.title')]), admin_webhooks_path, highlights_on: %r{/admin/webhooks}
|
||||
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? && !whitelist_mode? }, highlights_on: %r{/admin/relays}
|
||||
s.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_url, link_html: { target: 'sidekiq' }, if: -> { current_user.admin? }
|
||||
s.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_url, link_html: { target: 'pghero' }, if: -> { current_user.admin? }
|
||||
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) } do |s|
|
||||
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) }
|
||||
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings}
|
||||
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) }
|
||||
s.item :roles, safe_join([fa_icon('vcard fw'), t('admin.roles.title')]), admin_roles_path, highlights_on: %r{/admin/roles}, if: -> { current_user.can?(:manage_roles) }
|
||||
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}, if: -> { current_user.can?(:manage_announcements) }
|
||||
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_path, highlights_on: %r{/admin/custom_emojis}, if: -> { current_user.can?(:manage_custom_emojis) }
|
||||
s.item :webhooks, safe_join([fa_icon('inbox fw'), t('admin.webhooks.title')]), admin_webhooks_path, highlights_on: %r{/admin/webhooks}, if: -> { current_user.can?(:manage_webhooks) }
|
||||
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_path, highlights_on: %r{/admin/relays}, if: -> { !whitelist_mode? && current_user.can?(:manage_federation) }
|
||||
end
|
||||
|
||||
n.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_url, link_html: { 'data-method' => 'delete' }
|
||||
n.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_path, link_html: { target: 'sidekiq' }, if: -> { current_user.can?(:view_devops) }
|
||||
n.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_path, link_html: { target: 'pghero' }, if: -> { current_user.can?(:view_devops) }
|
||||
n.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
moderator:
|
||||
name: Moderator
|
||||
position: 10
|
||||
permissions:
|
||||
- view_dashboard
|
||||
- view_audit_log
|
||||
- manage_users
|
||||
- manage_reports
|
||||
- manage_taxonomies
|
||||
admin:
|
||||
name: Admin
|
||||
position: 100
|
||||
permissions:
|
||||
- view_dashboard
|
||||
- view_audit_log
|
||||
- manage_users
|
||||
- manage_user_access
|
||||
- delete_user_data
|
||||
- manage_reports
|
||||
- manage_taxonomies
|
||||
- manage_federation
|
||||
- manage_settings
|
||||
- manage_blocks
|
||||
- manage_appeals
|
||||
- manage_rules
|
||||
- manage_invites
|
||||
- manage_announcements
|
||||
- manage_custom_emojis
|
||||
- manage_webhooks
|
||||
- manage_roles
|
||||
owner:
|
||||
name: Owner
|
||||
position: 1000
|
||||
permissions:
|
||||
- administrator
|
|
@ -10,7 +10,7 @@ Rails.application.routes.draw do
|
|||
|
||||
get 'health', to: 'health#show'
|
||||
|
||||
authenticate :user, lambda { |u| u.admin? } do
|
||||
authenticate :user, lambda { |u| u.role&.can?(:view_devops) } do
|
||||
mount Sidekiq::Web, at: 'sidekiq', as: :sidekiq
|
||||
mount PgHero::Engine, at: 'pghero', as: :pghero
|
||||
end
|
||||
|
@ -295,17 +295,11 @@ Rails.application.routes.draw do
|
|||
post :resend
|
||||
end
|
||||
end
|
||||
|
||||
resource :role, only: [] do
|
||||
member do
|
||||
post :promote
|
||||
post :demote
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
resources :users, only: [] do
|
||||
resource :two_factor_authentication, only: [:destroy]
|
||||
resource :two_factor_authentication, only: [:destroy], controller: 'users/two_factor_authentications'
|
||||
resource :role, only: [:show, :update], controller: 'users/roles'
|
||||
end
|
||||
|
||||
resources :custom_emojis, only: [:index, :new, :create] do
|
||||
|
@ -320,6 +314,7 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
resources :roles, except: [:show]
|
||||
resources :account_moderation_notes, only: [:create, :destroy]
|
||||
resource :follow_recommendations, only: [:show, :update]
|
||||
resources :tags, only: [:show, :update]
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
class CreateUserRoles < ActiveRecord::Migration[6.1]
|
||||
def change
|
||||
create_table :user_roles do |t|
|
||||
t.string :name, null: false, default: ''
|
||||
t.string :color, null: false, default: ''
|
||||
t.integer :position, null: false, default: 0
|
||||
t.bigint :permissions, null: false, default: 0
|
||||
t.boolean :highlighted, null: false, default: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
class AddRoleIdToUsers < ActiveRecord::Migration[6.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
def change
|
||||
safety_assured { add_reference :users, :role, foreign_key: { to_table: 'user_roles', on_delete: :nullify }, index: false }
|
||||
add_index :users, :role_id, algorithm: :concurrently, where: 'role_id IS NOT NULL'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateRoles < ActiveRecord::Migration[5.2]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class UserRole < ApplicationRecord; end
|
||||
class User < ApplicationRecord; end
|
||||
|
||||
def up
|
||||
load Rails.root.join('db', 'seeds', '03_roles.rb')
|
||||
|
||||
admin_role = UserRole.find_by(name: 'Admin')
|
||||
moderator_role = UserRole.find_by(name: 'Moderator')
|
||||
|
||||
User.where(admin: true).in_batches.update_all(role_id: admin_role.id)
|
||||
User.where(moderator: true).in_batches.update_all(role_id: moderator_role.id)
|
||||
end
|
||||
|
||||
def down
|
||||
admin_role = UserRole.find_by(name: 'Admin')
|
||||
moderator_role = UserRole.find_by(name: 'Moderator')
|
||||
|
||||
User.where(role_id: admin_role.id).in_batches.update_all(admin: true) if admin_role
|
||||
User.where(role_id: moderator_role.id).in_batches.update_all(moderator: true) if moderator_role
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateSettingsToUserRoles < ActiveRecord::Migration[6.1]
|
||||
disable_ddl_transaction!
|
||||
|
||||
class UserRole < ApplicationRecord; end
|
||||
|
||||
def up
|
||||
owner_role = UserRole.find_by(name: 'Owner')
|
||||
admin_role = UserRole.find_by(name: 'Admin')
|
||||
moderator_role = UserRole.find_by(name: 'Moderator')
|
||||
everyone_role = UserRole.find_by(id: -99)
|
||||
|
||||
min_invite_role = Setting.min_invite_role
|
||||
show_staff_badge = Setting.show_staff_badge
|
||||
|
||||
if everyone_role
|
||||
everyone_role.permissions &= ~::UserRole::FLAGS[:invite_users] unless min_invite_role == 'user'
|
||||
everyone_role.save
|
||||
end
|
||||
|
||||
if owner_role
|
||||
owner_role.highlighted = show_staff_badge
|
||||
owner_role.save
|
||||
end
|
||||
|
||||
if admin_role
|
||||
admin_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(admin moderator).include?(min_invite_role)
|
||||
admin_role.highlighted = show_staff_badge
|
||||
admin_role.save
|
||||
end
|
||||
|
||||
if moderator_role
|
||||
moderator_role.permissions |= ::UserRole::FLAGS[:invite_users] if %w(moderator).include?(min_invite_role)
|
||||
moderator_role.highlighted = show_staff_badge
|
||||
moderator_role.save
|
||||
end
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
15
db/schema.rb
15
db/schema.rb
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_06_13_110903) do
|
||||
ActiveRecord::Schema.define(version: 2022_07_04_024901) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -968,6 +968,16 @@ ActiveRecord::Schema.define(version: 2022_06_13_110903) do
|
|||
t.index ["user_id"], name: "index_user_invite_requests_on_user_id"
|
||||
end
|
||||
|
||||
create_table "user_roles", force: :cascade do |t|
|
||||
t.string "name", default: "", null: false
|
||||
t.string "color", default: "", null: false
|
||||
t.integer "position", default: 0, null: false
|
||||
t.bigint "permissions", default: 0, null: false
|
||||
t.boolean "highlighted", default: false, null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
end
|
||||
|
||||
create_table "users", force: :cascade do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.datetime "created_at", null: false
|
||||
|
@ -1003,11 +1013,13 @@ ActiveRecord::Schema.define(version: 2022_06_13_110903) do
|
|||
t.string "webauthn_id"
|
||||
t.inet "sign_up_ip"
|
||||
t.boolean "skip_sign_in_token"
|
||||
t.bigint "role_id"
|
||||
t.index ["account_id"], name: "index_users_on_account_id"
|
||||
t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
|
||||
t.index ["created_by_application_id"], name: "index_users_on_created_by_application_id", where: "(created_by_application_id IS NOT NULL)"
|
||||
t.index ["email"], name: "index_users_on_email", unique: true
|
||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, opclass: :text_pattern_ops, where: "(reset_password_token IS NOT NULL)"
|
||||
t.index ["role_id"], name: "index_users_on_role_id", where: "(role_id IS NOT NULL)"
|
||||
end
|
||||
|
||||
create_table "web_push_subscriptions", force: :cascade do |t|
|
||||
|
@ -1159,6 +1171,7 @@ ActiveRecord::Schema.define(version: 2022_06_13_110903) do
|
|||
add_foreign_key "users", "accounts", name: "fk_50500f500d", on_delete: :cascade
|
||||
add_foreign_key "users", "invites", on_delete: :nullify
|
||||
add_foreign_key "users", "oauth_applications", column: "created_by_application_id", on_delete: :nullify
|
||||
add_foreign_key "users", "user_roles", column: "role_id", on_delete: :nullify
|
||||
add_foreign_key "web_push_subscriptions", "oauth_access_tokens", column: "access_token_id", on_delete: :cascade
|
||||
add_foreign_key "web_push_subscriptions", "users", on_delete: :cascade
|
||||
add_foreign_key "web_settings", "users", name: "fk_11910667b2", on_delete: :cascade
|
||||
|
|
12
db/seeds.rb
12
db/seeds.rb
|
@ -1,11 +1,5 @@
|
|||
Doorkeeper::Application.create!(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow push')
|
||||
# frozen_string_literal: true
|
||||
|
||||
domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
|
||||
account = Account.find_or_initialize_by(id: -99, actor_type: 'Application', locked: true, username: domain)
|
||||
account.save!
|
||||
|
||||
if Rails.env.development?
|
||||
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
|
||||
admin.save(validate: false)
|
||||
User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, admin: true, account: admin, agreement: true, approved: true).save!
|
||||
Dir[Rails.root.join('db', 'seeds', '*.rb')].sort.each do |seed|
|
||||
load seed
|
||||
end
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Doorkeeper::Application.create_with(name: 'Web', redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow push').find_or_create_by(superapp: true)
|
|
@ -0,0 +1 @@
|
|||
Account.create_with(actor_type: 'Application', locked: true, username: ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain).find_or_create_by(id: -99)
|
|
@ -0,0 +1,9 @@
|
|||
# Pre-create base role
|
||||
UserRole.everyone
|
||||
|
||||
# Create default roles defined in config file
|
||||
default_roles = YAML.load_file(Rails.root.join('config', 'roles.yml'))
|
||||
|
||||
default_roles.each do |_, config|
|
||||
UserRole.create_with(position: config['position'], permissions_as_keys: config['permissions'], highlighted: true).find_or_create_by(name: config['name'])
|
||||
end
|
|
@ -0,0 +1,8 @@
|
|||
if Rails.env.development?
|
||||
domain = ENV['LOCAL_DOMAIN'] || Rails.configuration.x.local_domain
|
||||
|
||||
admin = Account.where(username: 'admin').first_or_initialize(username: 'admin')
|
||||
admin.save(validate: false)
|
||||
|
||||
User.where(email: "admin@#{domain}").first_or_initialize(email: "admin@#{domain}", password: 'mastodonadmin', password_confirmation: 'mastodonadmin', confirmed_at: Time.now.utc, role: UserRole.find_by(name: 'Owner'), account: admin, agreement: true, approved: true).save!
|
||||
end
|
|
@ -54,7 +54,7 @@ module Mastodon
|
|||
|
||||
option :email, required: true
|
||||
option :confirmed, type: :boolean
|
||||
option :role, default: 'user', enum: %w(user moderator admin)
|
||||
option :role
|
||||
option :reattach, type: :boolean
|
||||
option :force, type: :boolean
|
||||
desc 'create USERNAME', 'Create a new user'
|
||||
|
@ -65,8 +65,7 @@ module Mastodon
|
|||
With the --confirmed option, the confirmation e-mail will
|
||||
be skipped and the account will be active straight away.
|
||||
|
||||
With the --role option one of "user", "admin" or "moderator"
|
||||
can be supplied. Defaults to "user"
|
||||
With the --role option, the role can be supplied.
|
||||
|
||||
With the --reattach option, the new user will be reattached
|
||||
to a given existing username of an old account. If the old
|
||||
|
@ -75,9 +74,22 @@ module Mastodon
|
|||
username to the new account anyway.
|
||||
LONG_DESC
|
||||
def create(username)
|
||||
role_id = nil
|
||||
|
||||
if options[:role]
|
||||
role = UserRole.find_by(name: options[:role])
|
||||
|
||||
if role.nil?
|
||||
say('Cannot find user role with that name', :red)
|
||||
exit(1)
|
||||
end
|
||||
|
||||
role_id = role.id
|
||||
end
|
||||
|
||||
account = Account.new(username: username)
|
||||
password = SecureRandom.hex
|
||||
user = User.new(email: options[:email], password: password, agreement: true, approved: true, admin: options[:role] == 'admin', moderator: options[:role] == 'moderator', confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true)
|
||||
user = User.new(email: options[:email], password: password, agreement: true, approved: true, role_id: role_id, confirmed_at: options[:confirmed] ? Time.now.utc : nil, bypass_invite_request_check: true)
|
||||
|
||||
if options[:reattach]
|
||||
account = Account.find_local(username) || Account.new(username: username)
|
||||
|
@ -106,14 +118,14 @@ module Mastodon
|
|||
user.errors.to_h.each do |key, error|
|
||||
say('Failure/Error: ', :red)
|
||||
say(key)
|
||||
say(' ' + error, :red)
|
||||
say(" #{error}", :red)
|
||||
end
|
||||
|
||||
exit(1)
|
||||
end
|
||||
end
|
||||
|
||||
option :role, enum: %w(user moderator admin)
|
||||
option :role
|
||||
option :email
|
||||
option :confirm, type: :boolean
|
||||
option :enable, type: :boolean
|
||||
|
@ -125,8 +137,7 @@ module Mastodon
|
|||
long_desc <<-LONG_DESC
|
||||
Modify a user account.
|
||||
|
||||
With the --role option, update the user's role to one of "user",
|
||||
"moderator" or "admin".
|
||||
With the --role option, update the user's role.
|
||||
|
||||
With the --email option, update the user's e-mail address. With
|
||||
the --confirm option, mark the user's e-mail as confirmed.
|
||||
|
@ -152,8 +163,14 @@ module Mastodon
|
|||
end
|
||||
|
||||
if options[:role]
|
||||
user.admin = options[:role] == 'admin'
|
||||
user.moderator = options[:role] == 'moderator'
|
||||
role = UserRole.find_by(name: options[:role])
|
||||
|
||||
if role.nil?
|
||||
say('Cannot find user role with that name', :red)
|
||||
exit(1)
|
||||
end
|
||||
|
||||
user.role_id = role.id
|
||||
end
|
||||
|
||||
password = SecureRandom.hex if options[:reset_password]
|
||||
|
@ -172,7 +189,7 @@ module Mastodon
|
|||
user.errors.to_h.each do |key, error|
|
||||
say('Failure/Error: ', :red)
|
||||
say(key)
|
||||
say(' ' + error, :red)
|
||||
say(" #{error}", :red)
|
||||
end
|
||||
|
||||
exit(1)
|
||||
|
@ -319,7 +336,7 @@ module Mastodon
|
|||
|
||||
unless skip_domains.empty?
|
||||
say('The following domains were not available during the check:', :yellow)
|
||||
skip_domains.each { |domain| say(' ' + domain) }
|
||||
skip_domains.each { |domain| say(" #{domain}") }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SimpleNavigation
|
||||
module ItemExtensions
|
||||
def url
|
||||
if @url.nil? && @sub_navigation
|
||||
@sub_navigation.items.first.url
|
||||
else
|
||||
@url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SimpleNavigation::Item.prepend(SimpleNavigation::ItemExtensions)
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Admin::AccountModerationNotesController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
|
||||
before do
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
before { sign_in current_user, scope: :user }
|
||||
|
||||
describe 'GET #index' do
|
||||
let(:current_user) { Fabricate(:user, admin: true) }
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
around do |example|
|
||||
default_per_page = Account.default_per_page
|
||||
|
@ -60,7 +60,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
let(:current_user) { Fabricate(:user, admin: true) }
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
it 'returns http success' do
|
||||
|
@ -72,15 +72,15 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
describe 'POST #memorialize' do
|
||||
subject { post :memorialize, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: current_user_admin) }
|
||||
let(:current_user) { Fabricate(:user, role: current_role) }
|
||||
let(:account) { user.account }
|
||||
let(:user) { Fabricate(:user, admin: target_user_admin) }
|
||||
let(:user) { Fabricate(:user, role: target_role) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:current_user_admin) { true }
|
||||
let(:current_role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
context 'when target user is admin' do
|
||||
let(:target_user_admin) { true }
|
||||
let(:target_role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'fails to memorialize account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -89,7 +89,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when target user is not admin' do
|
||||
let(:target_user_admin) { false }
|
||||
let(:target_role) { UserRole.find_by(name: 'Moderator') }
|
||||
|
||||
it 'succeeds in memorializing account' do
|
||||
is_expected.to redirect_to admin_account_path(account.id)
|
||||
|
@ -99,10 +99,10 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:current_user_admin) { false }
|
||||
let(:current_role) { UserRole.find_by(name: 'Moderator') }
|
||||
|
||||
context 'when target user is admin' do
|
||||
let(:target_user_admin) { true }
|
||||
let(:target_role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'fails to memorialize account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -111,7 +111,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when target user is not admin' do
|
||||
let(:target_user_admin) { false }
|
||||
let(:target_role) { UserRole.find_by(name: 'Moderator') }
|
||||
|
||||
it 'fails to memorialize account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -124,12 +124,12 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
describe 'POST #enable' do
|
||||
subject { post :enable, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { user.account }
|
||||
let(:user) { Fabricate(:user, disabled: true) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in enabling account' do
|
||||
is_expected.to redirect_to admin_account_path(account.id)
|
||||
|
@ -138,7 +138,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to enable account' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -150,19 +150,23 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
describe 'POST #redownload' do
|
||||
subject { post :redownload, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { Fabricate(:account, domain: 'example.com') }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(ResolveAccountService).to receive(:call)
|
||||
end
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in redownloadin' do
|
||||
it 'succeeds in redownloading' do
|
||||
is_expected.to redirect_to admin_account_path(account.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to redownload' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -173,11 +177,11 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
describe 'POST #remove_avatar' do
|
||||
subject { post :remove_avatar, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in removing avatar' do
|
||||
is_expected.to redirect_to admin_account_path(account.id)
|
||||
|
@ -185,7 +189,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to remove avatar' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
@ -196,12 +200,12 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
describe 'POST #unblock_email' do
|
||||
subject { post :unblock_email, params: { id: account.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { Fabricate(:account, suspended: true) }
|
||||
let!(:email_block) { Fabricate(:canonical_email_block, reference_account: account) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in removing email blocks' do
|
||||
expect { subject }.to change { CanonicalEmailBlock.where(reference_account: account).count }.from(1).to(0)
|
||||
|
@ -214,7 +218,7 @@ RSpec.describe Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
let(:role) { UserRole.everyone }
|
||||
|
||||
it 'fails to remove avatar' do
|
||||
subject
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'rails_helper'
|
|||
describe Admin::ActionLogsController, type: :controller do
|
||||
describe 'GET #index' do
|
||||
it 'returns 200' do
|
||||
sign_in Fabricate(:user, admin: true)
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
|
||||
get :index, params: { page: 1 }
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -5,13 +5,14 @@ require 'rails_helper'
|
|||
describe Admin::BaseController, type: :controller do
|
||||
controller do
|
||||
def success
|
||||
authorize :dashboard, :index?
|
||||
render 'admin/reports/show'
|
||||
end
|
||||
end
|
||||
|
||||
it 'requires administrator or moderator' do
|
||||
routes.draw { get 'success' => 'admin/base#success' }
|
||||
sign_in(Fabricate(:user, admin: false, moderator: false))
|
||||
sign_in(Fabricate(:user))
|
||||
get :success
|
||||
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
|
@ -19,14 +20,14 @@ describe Admin::BaseController, type: :controller do
|
|||
|
||||
it 'renders admin layout as a moderator' do
|
||||
routes.draw { get 'success' => 'admin/base#success' }
|
||||
sign_in(Fabricate(:user, moderator: true))
|
||||
sign_in(Fabricate(:user, role: UserRole.find_by(name: 'Moderator')))
|
||||
get :success
|
||||
expect(response).to render_template layout: 'admin'
|
||||
end
|
||||
|
||||
it 'renders admin layout as an admin' do
|
||||
routes.draw { get 'success' => 'admin/base#success' }
|
||||
sign_in(Fabricate(:user, admin: true))
|
||||
sign_in(Fabricate(:user, role: UserRole.find_by(name: 'Admin')))
|
||||
get :success
|
||||
expect(response).to render_template layout: 'admin'
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Admin::ChangeEmailsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:admin) { Fabricate(:user, admin: true) }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in admin
|
||||
|
|
|
@ -4,7 +4,7 @@ RSpec.describe Admin::ConfirmationsController, type: :controller do
|
|||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe Admin::CustomEmojisController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
|
|
|
@ -12,7 +12,7 @@ describe Admin::DashboardController, type: :controller do
|
|||
Admin::SystemCheck::Message.new(:rules_check, nil, admin_rules_path),
|
||||
Admin::SystemCheck::Message.new(:sidekiq_process_check, 'foo, bar'),
|
||||
])
|
||||
sign_in Fabricate(:user, admin: true)
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
|
||||
end
|
||||
|
||||
it 'returns 200' do
|
||||
|
|
|
@ -14,7 +14,7 @@ RSpec.describe Admin::Disputes::AppealsController, type: :controller do
|
|||
end
|
||||
|
||||
describe 'POST #approve' do
|
||||
let(:current_user) { Fabricate(:user, admin: true) }
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:appeal_approved).and_return(double('email', deliver_later: nil))
|
||||
|
@ -35,7 +35,7 @@ RSpec.describe Admin::Disputes::AppealsController, type: :controller do
|
|||
end
|
||||
|
||||
describe 'POST #reject' do
|
||||
let(:current_user) { Fabricate(:user, admin: true) }
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
allow(UserMailer).to receive(:appeal_rejected).and_return(double('email', deliver_later: nil))
|
||||
|
|
|
@ -4,7 +4,7 @@ RSpec.describe Admin::DomainBlocksController, type: :controller do
|
|||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #new' do
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Admin::EmailDomainBlocksController, type: :controller do
|
|||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Admin::InstancesController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: true) }
|
||||
let(:current_user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
let!(:account) { Fabricate(:account, domain: 'popular') }
|
||||
let!(:account2) { Fabricate(:account, domain: 'popular') }
|
||||
|
@ -35,11 +35,11 @@ RSpec.describe Admin::InstancesController, type: :controller do
|
|||
describe 'DELETE #destroy' do
|
||||
subject { delete :destroy, params: { id: Instance.first.id } }
|
||||
|
||||
let(:current_user) { Fabricate(:user, admin: admin) }
|
||||
let(:current_user) { Fabricate(:user, role: role) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
|
||||
context 'when user is admin' do
|
||||
let(:admin) { true }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
|
||||
it 'succeeds in purging instance' do
|
||||
is_expected.to redirect_to admin_instances_path
|
||||
|
@ -47,7 +47,7 @@ RSpec.describe Admin::InstancesController, type: :controller do
|
|||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:admin) { false }
|
||||
let(:role) { nil }
|
||||
|
||||
it 'fails to purge instance' do
|
||||
is_expected.to have_http_status :forbidden
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'rails_helper'
|
|||
describe Admin::InvitesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe Admin::ReportNotesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe Admin::ReportsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
before do
|
||||
sign_in user, scope: :user
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ describe Admin::ResetsController do
|
|||
|
||||
let(:account) { Fabricate(:account) }
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
|
|
|
@ -3,31 +3,247 @@ require 'rails_helper'
|
|||
describe Admin::RolesController do
|
||||
render_views
|
||||
|
||||
let(:admin) { Fabricate(:user, admin: true) }
|
||||
let(:permissions) { UserRole::Flags::NONE }
|
||||
let(:current_role) { UserRole.create(name: 'Foo', permissions: permissions, position: 10) }
|
||||
let(:current_user) { Fabricate(:user, role: current_role) }
|
||||
|
||||
before do
|
||||
sign_in admin, scope: :user
|
||||
sign_in current_user, scope: :user
|
||||
end
|
||||
|
||||
describe 'POST #promote' do
|
||||
subject { post :promote, params: { account_id: user.account_id } }
|
||||
describe 'GET #index' do
|
||||
before do
|
||||
get :index
|
||||
end
|
||||
|
||||
let(:user) { Fabricate(:user, moderator: false, admin: false) }
|
||||
context 'when user does not have permission to manage roles' do
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
it 'promotes user' do
|
||||
expect(subject).to redirect_to admin_account_path(user.account_id)
|
||||
expect(user.reload).to be_moderator
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #demote' do
|
||||
subject { post :demote, params: { account_id: user.account_id } }
|
||||
describe 'GET #new' do
|
||||
before do
|
||||
get :new
|
||||
end
|
||||
|
||||
let(:user) { Fabricate(:user, moderator: true, admin: false) }
|
||||
context 'when user does not have permission to manage roles' do
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
it 'demotes user' do
|
||||
expect(subject).to redirect_to admin_account_path(user.account_id)
|
||||
expect(user.reload).not_to be_moderator
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let(:selected_position) { 1 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_roles) }
|
||||
|
||||
before do
|
||||
post :create, params: { user_role: { name: 'Bar', position: selected_position, permissions_as_keys: selected_permissions_as_keys } }
|
||||
end
|
||||
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
context 'when new role\'s does not elevate above the user\'s role' do
|
||||
let(:selected_position) { 1 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_roles) }
|
||||
|
||||
it 'redirects to roles page' do
|
||||
expect(response).to redirect_to(admin_roles_path)
|
||||
end
|
||||
|
||||
it 'creates new role' do
|
||||
expect(UserRole.find_by(name: 'Bar')).to_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when new role\'s position is higher than user\'s role' do
|
||||
let(:selected_position) { 100 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_roles) }
|
||||
|
||||
it 'renders new template' do
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
|
||||
it 'does not create new role' do
|
||||
expect(UserRole.find_by(name: 'Bar')).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when new role has permissions the user does not have' do
|
||||
let(:selected_position) { 1 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_roles manage_users manage_reports) }
|
||||
|
||||
it 'renders new template' do
|
||||
expect(response).to render_template(:new)
|
||||
end
|
||||
|
||||
it 'does not create new role' do
|
||||
expect(UserRole.find_by(name: 'Bar')).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has administrator permission' do
|
||||
let(:permissions) { UserRole::FLAGS[:administrator] }
|
||||
|
||||
let(:selected_position) { 1 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_roles manage_users manage_reports) }
|
||||
|
||||
it 'redirects to roles page' do
|
||||
expect(response).to redirect_to(admin_roles_path)
|
||||
end
|
||||
|
||||
it 'creates new role' do
|
||||
expect(UserRole.find_by(name: 'Bar')).to_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #edit' do
|
||||
let(:role_position) { 8 }
|
||||
let(:role) { UserRole.create(name: 'Bar', permissions: UserRole::FLAGS[:manage_users], position: role_position) }
|
||||
|
||||
before do
|
||||
get :edit, params: { id: role.id }
|
||||
end
|
||||
|
||||
context 'when user does not have permission to manage roles' do
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
context 'when user outranks the role' do
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when role outranks user' do
|
||||
let(:role_position) { current_role.position + 1 }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let(:role_position) { 8 }
|
||||
let(:role_permissions) { UserRole::FLAGS[:manage_users] }
|
||||
let(:role) { UserRole.create(name: 'Bar', permissions: role_permissions, position: role_position) }
|
||||
|
||||
let(:selected_position) { 8 }
|
||||
let(:selected_permissions_as_keys) { %w(manage_users) }
|
||||
|
||||
before do
|
||||
put :update, params: { id: role.id, user_role: { name: 'Baz', position: selected_position, permissions_as_keys: selected_permissions_as_keys } }
|
||||
end
|
||||
|
||||
context 'when user does not have permission to manage roles' do
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
|
||||
it 'does not update the role' do
|
||||
expect(role.reload.name).to eq 'Bar'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
context 'when role has permissions the user doesn\'t' do
|
||||
it 'renders edit template' do
|
||||
expect(response).to render_template(:edit)
|
||||
end
|
||||
|
||||
it 'does not update the role' do
|
||||
expect(role.reload.name).to eq 'Bar'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has all permissions of the role' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] | UserRole::FLAGS[:manage_users] }
|
||||
|
||||
context 'when user outranks the role' do
|
||||
it 'redirects to roles page' do
|
||||
expect(response).to redirect_to(admin_roles_path)
|
||||
end
|
||||
|
||||
it 'updates the role' do
|
||||
expect(role.reload.name).to eq 'Baz'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when role outranks user' do
|
||||
let(:role_position) { current_role.position + 1 }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
|
||||
it 'does not update the role' do
|
||||
expect(role.reload.name).to eq 'Bar'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
||||
let(:role_position) { 8 }
|
||||
let(:role) { UserRole.create(name: 'Bar', permissions: UserRole::FLAGS[:manage_users], position: role_position) }
|
||||
|
||||
before do
|
||||
delete :destroy, params: { id: role.id }
|
||||
end
|
||||
|
||||
context 'when user does not have permission to manage roles' do
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has permission to manage roles' do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
|
||||
context 'when user outranks the role' do
|
||||
it 'redirects to roles page' do
|
||||
expect(response).to redirect_to(admin_roles_path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when role outranks user' do
|
||||
let(:role_position) { current_role.position + 1 }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ RSpec.describe Admin::SettingsController, type: :controller do
|
|||
|
||||
describe 'When signed in as an admin' do
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #edit' do
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
describe Admin::StatusesController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user, admin: true) }
|
||||
let(:user) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:account) { Fabricate(:account) }
|
||||
let!(:status) { Fabricate(:status, account: account) }
|
||||
let(:media_attached_status) { Fabricate(:status, account: account, sensitive: !sensitive) }
|
||||
|
|
|
@ -6,7 +6,7 @@ RSpec.describe Admin::TagsController, type: :controller do
|
|||
render_views
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true)
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin'))
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe Admin::Users::RolesController do
|
||||
render_views
|
||||
|
||||
let(:current_role) { UserRole.create(name: 'Foo', permissions: UserRole::FLAGS[:manage_roles], position: 10) }
|
||||
let(:current_user) { Fabricate(:user, role: current_role) }
|
||||
|
||||
let(:previous_role) { nil }
|
||||
let(:user) { Fabricate(:user, role: previous_role) }
|
||||
|
||||
before do
|
||||
sign_in current_user, scope: :user
|
||||
end
|
||||
|
||||
describe 'GET #show' do
|
||||
before do
|
||||
get :show, params: { user_id: user.id }
|
||||
end
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
context 'when target user is higher ranked than current user' do
|
||||
let(:previous_role) { UserRole.create(name: 'Baz', permissions: UserRole::FLAGS[:administrator], position: 100) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
let(:selected_role) { UserRole.create(name: 'Bar', permissions: permissions, position: position) }
|
||||
|
||||
before do
|
||||
put :update, params: { user_id: user.id, user: { role_id: selected_role.id } }
|
||||
end
|
||||
|
||||
context do
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
let(:position) { 1 }
|
||||
|
||||
it 'updates user role' do
|
||||
expect(user.reload.role_id).to eq selected_role&.id
|
||||
end
|
||||
|
||||
it 'redirects back to account page' do
|
||||
expect(response).to redirect_to(admin_account_path(user.account_id))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when selected role has higher position than current user\'s role' do
|
||||
let(:permissions) { UserRole::FLAGS[:administrator] }
|
||||
let(:position) { 100 }
|
||||
|
||||
it 'does not update user role' do
|
||||
expect(user.reload.role_id).to eq previous_role&.id
|
||||
end
|
||||
|
||||
it 'renders edit form' do
|
||||
expect(response).to render_template(:show)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when target user is higher ranked than current user' do
|
||||
let(:previous_role) { UserRole.create(name: 'Baz', permissions: UserRole::FLAGS[:administrator], position: 100) }
|
||||
let(:permissions) { UserRole::FLAGS[:manage_roles] }
|
||||
let(:position) { 1 }
|
||||
|
||||
it 'does not update user role' do
|
||||
expect(user.reload.role_id).to eq previous_role&.id
|
||||
end
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(:forbidden)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,12 +1,13 @@
|
|||
require 'rails_helper'
|
||||
require 'webauthn/fake_client'
|
||||
|
||||
describe Admin::TwoFactorAuthenticationsController do
|
||||
describe Admin::Users::TwoFactorAuthenticationsController do
|
||||
render_views
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
sign_in Fabricate(:user, admin: true), scope: :user
|
||||
sign_in Fabricate(:user, role: UserRole.find_by(name: 'Admin')), scope: :user
|
||||
end
|
||||
|
||||
describe 'DELETE #destroy' do
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V1::Admin::AccountActionsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'moderator' }
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -22,7 +22,7 @@ RSpec.describe Api::V1::Admin::AccountActionsController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -35,7 +35,7 @@ RSpec.describe Api::V1::Admin::AccountActionsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'moderator' }
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -22,7 +22,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -46,7 +46,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
[
|
||||
[{ active: 'true', local: 'true', staff: 'true' }, [:admin_account]],
|
||||
|
@ -77,7 +77,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -91,7 +91,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -109,7 +109,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -127,7 +127,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -145,7 +145,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -163,7 +163,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -181,7 +181,7 @@ RSpec.describe Api::V1::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'admin' }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -21,7 +21,7 @@ RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -36,8 +36,8 @@ RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -58,8 +58,8 @@ RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -79,8 +79,8 @@ RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -99,8 +99,8 @@ RSpec.describe Api::V1::Admin::DomainAllowsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'admin' }
|
||||
let(:role) { UserRole.find_by(name: 'Admin') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -21,7 +21,7 @@ RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -36,8 +36,8 @@ RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -58,8 +58,8 @@ RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -79,8 +79,8 @@ RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -100,8 +100,8 @@ RSpec.describe Api::V1::Admin::DomainBlocksController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', 'moderator'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
it_behaves_like 'forbidden for wrong role', 'Moderator'
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'moderator' }
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -22,7 +22,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -35,7 +35,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -48,7 +48,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -61,7 +61,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -74,7 +74,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -87,7 +87,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
@ -100,7 +100,7 @@ RSpec.describe Api::V1::Admin::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
it 'returns http success' do
|
||||
expect(response).to have_http_status(200)
|
||||
|
|
|
@ -13,7 +13,7 @@ RSpec.describe Api::V1::ReportsController, type: :controller do
|
|||
end
|
||||
|
||||
describe 'POST #create' do
|
||||
let!(:admin) { Fabricate(:user, admin: true) }
|
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
let(:scopes) { 'write:reports' }
|
||||
let(:status) { Fabricate(:status) }
|
||||
|
|
|
@ -3,7 +3,7 @@ require 'rails_helper'
|
|||
RSpec.describe Api::V2::Admin::AccountsController, type: :controller do
|
||||
render_views
|
||||
|
||||
let(:role) { 'moderator' }
|
||||
let(:role) { UserRole.find_by(name: 'Moderator') }
|
||||
let(:user) { Fabricate(:user, role: role) }
|
||||
let(:scopes) { 'admin:read admin:write' }
|
||||
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) }
|
||||
|
@ -22,7 +22,7 @@ RSpec.describe Api::V2::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
shared_examples 'forbidden for wrong role' do |wrong_role|
|
||||
let(:role) { wrong_role }
|
||||
let(:role) { UserRole.find_by(name: wrong_role) }
|
||||
|
||||
it 'returns http forbidden' do
|
||||
expect(response).to have_http_status(403)
|
||||
|
@ -46,7 +46,7 @@ RSpec.describe Api::V2::Admin::AccountsController, type: :controller do
|
|||
end
|
||||
|
||||
it_behaves_like 'forbidden for wrong scope', 'write:statuses'
|
||||
it_behaves_like 'forbidden for wrong role', 'user'
|
||||
it_behaves_like 'forbidden for wrong role', ''
|
||||
|
||||
[
|
||||
[{ status: 'active', origin: 'local', permissions: 'staff' }, [:admin_account]],
|
||||
|
|
|
@ -183,70 +183,6 @@ describe ApplicationController, type: :controller do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'require_admin!' do
|
||||
controller do
|
||||
before_action :require_admin!
|
||||
|
||||
def success
|
||||
head 200
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
routes.draw { get 'success' => 'anonymous#success' }
|
||||
end
|
||||
|
||||
it 'returns a 403 if current user is not admin' do
|
||||
sign_in(Fabricate(:user, admin: false))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
|
||||
it 'returns a 403 if current user is only a moderator' do
|
||||
sign_in(Fabricate(:user, moderator: true))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
|
||||
it 'does nothing if current user is admin' do
|
||||
sign_in(Fabricate(:user, admin: true))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'require_staff!' do
|
||||
controller do
|
||||
before_action :require_staff!
|
||||
|
||||
def success
|
||||
head 200
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
routes.draw { get 'success' => 'anonymous#success' }
|
||||
end
|
||||
|
||||
it 'returns a 403 if current user is not admin or moderator' do
|
||||
sign_in(Fabricate(:user, admin: false, moderator: false))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(403)
|
||||
end
|
||||
|
||||
it 'does nothing if current user is moderator' do
|
||||
sign_in(Fabricate(:user, moderator: true))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
|
||||
it 'does nothing if current user is admin' do
|
||||
sign_in(Fabricate(:user, admin: true))
|
||||
get 'success'
|
||||
expect(response).to have_http_status(200)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'forbidden' do
|
||||
controller do
|
||||
def route_forbidden
|
||||
|
|
|
@ -5,7 +5,7 @@ RSpec.describe Disputes::AppealsController, type: :controller do
|
|||
|
||||
before { sign_in current_user, scope: :user }
|
||||
|
||||
let!(:admin) { Fabricate(:user, admin: true) }
|
||||
let!(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
|
||||
describe '#create' do
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
|
|
|
@ -7,30 +7,30 @@ describe InvitesController do
|
|||
sign_in user
|
||||
end
|
||||
|
||||
around do |example|
|
||||
min_invite_role = Setting.min_invite_role
|
||||
example.run
|
||||
Setting.min_invite_role = min_invite_role
|
||||
end
|
||||
|
||||
describe 'GET #index' do
|
||||
subject { get :index }
|
||||
|
||||
let(:user) { Fabricate(:user, moderator: false, admin: false) }
|
||||
let(:user) { Fabricate(:user) }
|
||||
let!(:invite) { Fabricate(:invite, user: user) }
|
||||
|
||||
context 'when user is a staff' do
|
||||
context 'when everyone can invite' do
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole.everyone.permissions | UserRole::FLAGS[:invite_users])
|
||||
end
|
||||
|
||||
it 'renders index page' do
|
||||
Setting.min_invite_role = 'user'
|
||||
expect(subject).to render_template :index
|
||||
expect(assigns(:invites)).to include invite
|
||||
expect(assigns(:invites).count).to eq 1
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not a staff' do
|
||||
context 'when not everyone can invite' do
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole.everyone.permissions & ~UserRole::FLAGS[:invite_users])
|
||||
end
|
||||
|
||||
it 'returns 403' do
|
||||
Setting.min_invite_role = 'modelator'
|
||||
expect(subject).to have_http_status 403
|
||||
end
|
||||
end
|
||||
|
@ -39,8 +39,12 @@ describe InvitesController do
|
|||
describe 'POST #create' do
|
||||
subject { post :create, params: { invite: { max_uses: '10', expires_in: 1800 } } }
|
||||
|
||||
context 'when user is an admin' do
|
||||
let(:user) { Fabricate(:user, moderator: false, admin: true) }
|
||||
context 'when everyone can invite' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole.everyone.permissions | UserRole::FLAGS[:invite_users])
|
||||
end
|
||||
|
||||
it 'succeeds to create a invite' do
|
||||
expect { subject }.to change { Invite.count }.by(1)
|
||||
|
@ -49,8 +53,12 @@ describe InvitesController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when user is not an admin' do
|
||||
let(:user) { Fabricate(:user, moderator: true, admin: false) }
|
||||
context 'when not everyone can invite' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole.everyone.permissions & ~UserRole::FLAGS[:invite_users])
|
||||
end
|
||||
|
||||
it 'returns 403' do
|
||||
expect(subject).to have_http_status 403
|
||||
|
@ -61,8 +69,8 @@ describe InvitesController do
|
|||
describe 'DELETE #create' do
|
||||
subject { delete :destroy, params: { id: invite.id } }
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
let!(:invite) { Fabricate(:invite, user: user, expires_at: nil) }
|
||||
let(:user) { Fabricate(:user, moderator: false, admin: true) }
|
||||
|
||||
it 'expires invite' do
|
||||
expect(subject).to redirect_to invites_path
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
Fabricator(:user_role) do
|
||||
name "MyString"
|
||||
color "MyString"
|
||||
permissions ""
|
||||
end
|
|
@ -445,7 +445,7 @@ RSpec.describe Account, type: :model do
|
|||
|
||||
it 'accepts arbitrary limits' do
|
||||
2.times.each { Fabricate(:account, display_name: "Display Name") }
|
||||
results = Account.search_for("display", 1)
|
||||
results = Account.search_for("display", limit: 1)
|
||||
expect(results.size).to eq 1
|
||||
end
|
||||
|
||||
|
@ -473,7 +473,7 @@ RSpec.describe Account, type: :model do
|
|||
)
|
||||
account.follow!(match)
|
||||
|
||||
results = Account.advanced_search_for('A?l\i:c e', account, 10, true)
|
||||
results = Account.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
|
||||
expect(results).to eq [match]
|
||||
end
|
||||
|
||||
|
@ -485,7 +485,7 @@ RSpec.describe Account, type: :model do
|
|||
domain: 'example.com'
|
||||
)
|
||||
|
||||
results = Account.advanced_search_for('A?l\i:c e', account, 10, true)
|
||||
results = Account.advanced_search_for('A?l\i:c e', account, limit: 10, following: true)
|
||||
expect(results).to eq []
|
||||
end
|
||||
|
||||
|
@ -498,7 +498,7 @@ RSpec.describe Account, type: :model do
|
|||
suspended: true
|
||||
)
|
||||
|
||||
results = Account.advanced_search_for('username', account, 10, true)
|
||||
results = Account.advanced_search_for('username', account, limit: 10, following: true)
|
||||
expect(results).to eq []
|
||||
end
|
||||
|
||||
|
@ -511,7 +511,7 @@ RSpec.describe Account, type: :model do
|
|||
|
||||
match.user.update(approved: false)
|
||||
|
||||
results = Account.advanced_search_for('username', account, 10, true)
|
||||
results = Account.advanced_search_for('username', account, limit: 10, following: true)
|
||||
expect(results).to eq []
|
||||
end
|
||||
|
||||
|
@ -524,7 +524,7 @@ RSpec.describe Account, type: :model do
|
|||
|
||||
match.user.update(confirmed_at: nil)
|
||||
|
||||
results = Account.advanced_search_for('username', account, 10, true)
|
||||
results = Account.advanced_search_for('username', account, limit: 10, following: true)
|
||||
expect(results).to eq []
|
||||
end
|
||||
end
|
||||
|
@ -588,7 +588,7 @@ RSpec.describe Account, type: :model do
|
|||
|
||||
it 'accepts arbitrary limits' do
|
||||
2.times { Fabricate(:account, display_name: "Display Name") }
|
||||
results = Account.advanced_search_for("display", account, 1)
|
||||
results = Account.advanced_search_for("display", account, limit: 1)
|
||||
expect(results.size).to eq 1
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ RSpec.describe Admin::AccountAction, type: :model do
|
|||
|
||||
describe '#save!' do
|
||||
subject { account_action.save! }
|
||||
let(:account) { Fabricate(:user, admin: true).account }
|
||||
let(:account) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:target_account) { Fabricate(:account) }
|
||||
let(:type) { 'disable' }
|
||||
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe UserRole, type: :model do
|
||||
subject { described_class.create(name: 'Foo', position: 1) }
|
||||
|
||||
describe '#can?' do
|
||||
context 'with a single flag' do
|
||||
it 'returns true if any of them are present' do
|
||||
subject.permissions = UserRole::FLAGS[:manage_reports]
|
||||
expect(subject.can?(:manage_reports)).to be true
|
||||
end
|
||||
|
||||
it 'returns false if it is not set' do
|
||||
expect(subject.can?(:manage_reports)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple flags' do
|
||||
it 'returns true if any of them are present' do
|
||||
subject.permissions = UserRole::FLAGS[:manage_users]
|
||||
expect(subject.can?(:manage_reports, :manage_users)).to be true
|
||||
end
|
||||
|
||||
it 'returns false if none of them are present' do
|
||||
expect(subject.can?(:manage_reports, :manage_users)).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unknown flag' do
|
||||
it 'raises an error' do
|
||||
expect { subject.can?(:foo) }.to raise_error ArgumentError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#overrides?' do
|
||||
it 'returns true if other role has lower position' do
|
||||
expect(subject.overrides?(described_class.new(position: subject.position - 1))).to be true
|
||||
end
|
||||
|
||||
it 'returns true if other role is nil' do
|
||||
expect(subject.overrides?(nil)).to be true
|
||||
end
|
||||
|
||||
it 'returns false if other role has higher position' do
|
||||
expect(subject.overrides?(described_class.new(position: subject.position + 1))).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#permissions_as_keys' do
|
||||
before do
|
||||
subject.permissions = UserRole::FLAGS[:invite_users] | UserRole::FLAGS[:view_dashboard] | UserRole::FLAGS[:manage_reports]
|
||||
end
|
||||
|
||||
it 'returns an array' do
|
||||
expect(subject.permissions_as_keys).to match_array %w(invite_users view_dashboard manage_reports)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#permissions_as_keys=' do
|
||||
let(:input) { }
|
||||
|
||||
before do
|
||||
subject.permissions_as_keys = input
|
||||
end
|
||||
|
||||
context 'with a single value' do
|
||||
let(:input) { %w(manage_users) }
|
||||
|
||||
it 'sets permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with multiple values' do
|
||||
let(:input) { %w(manage_users manage_reports) }
|
||||
|
||||
it 'sets permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::FLAGS[:manage_users] | UserRole::FLAGS[:manage_reports]
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an unknown value' do
|
||||
let(:input) { %w(foo) }
|
||||
|
||||
it 'does not set permission flags' do
|
||||
expect(subject.permissions).to eq UserRole::Flags::NONE
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#computed_permissions' do
|
||||
context 'when the role is nobody' do
|
||||
let(:subject) { described_class.nobody }
|
||||
|
||||
it 'returns none' do
|
||||
expect(subject.computed_permissions).to eq UserRole::Flags::NONE
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the role is everyone' do
|
||||
let(:subject) { described_class.everyone }
|
||||
|
||||
it 'returns permissions' do
|
||||
expect(subject.computed_permissions).to eq subject.permissions
|
||||
end
|
||||
end
|
||||
|
||||
context 'when role has the administrator flag' do
|
||||
before do
|
||||
subject.permissions = UserRole::FLAGS[:administrator]
|
||||
end
|
||||
|
||||
it 'returns all permissions' do
|
||||
expect(subject.computed_permissions).to eq UserRole::Flags::ALL
|
||||
end
|
||||
end
|
||||
|
||||
context do
|
||||
it 'returns permissions combined with the everyone role' do
|
||||
expect(subject.computed_permissions).to eq described_class.everyone.permissions
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.everyone' do
|
||||
subject { described_class.everyone }
|
||||
|
||||
it 'returns a role' do
|
||||
expect(subject).to be_kind_of(described_class)
|
||||
end
|
||||
|
||||
it 'is identified as the everyone role' do
|
||||
expect(subject.everyone?).to be true
|
||||
end
|
||||
|
||||
it 'has default permissions' do
|
||||
expect(subject.permissions).to eq UserRole::FLAGS[:invite_users]
|
||||
end
|
||||
|
||||
it 'has negative position' do
|
||||
expect(subject.position).to eq -1
|
||||
end
|
||||
end
|
||||
|
||||
describe '.nobody' do
|
||||
subject { described_class.nobody }
|
||||
|
||||
it 'returns a role' do
|
||||
expect(subject).to be_kind_of(described_class)
|
||||
end
|
||||
|
||||
it 'is identified as the nobody role' do
|
||||
expect(subject.nobody?).to be true
|
||||
end
|
||||
|
||||
it 'has no permissions' do
|
||||
expect(subject.permissions).to eq UserRole::Flags::NONE
|
||||
end
|
||||
|
||||
it 'has negative position' do
|
||||
expect(subject.position).to eq -1
|
||||
end
|
||||
end
|
||||
|
||||
describe '#everyone?' do
|
||||
it 'returns true when id is -99' do
|
||||
subject.id = -99
|
||||
expect(subject.everyone?).to be true
|
||||
end
|
||||
|
||||
it 'returns false when id is not -99' do
|
||||
subject.id = 123
|
||||
expect(subject.everyone?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
describe '#nobody?' do
|
||||
it 'returns true when id is nil' do
|
||||
subject.id = nil
|
||||
expect(subject.nobody?).to be true
|
||||
end
|
||||
|
||||
it 'returns false when id is not nil' do
|
||||
subject.id = 123
|
||||
expect(subject.nobody?).to be false
|
||||
end
|
||||
end
|
||||
end
|
|
@ -56,14 +56,6 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'admins' do
|
||||
it 'returns an array of users who are admin' do
|
||||
user_1 = Fabricate(:user, admin: false)
|
||||
user_2 = Fabricate(:user, admin: true)
|
||||
expect(User.admins).to match_array([user_2])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'confirmed' do
|
||||
it 'returns an array of users who are confirmed' do
|
||||
user_1 = Fabricate(:user, confirmed_at: nil)
|
||||
|
@ -289,49 +281,6 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#role' do
|
||||
it 'returns admin for admin' do
|
||||
user = User.new(admin: true)
|
||||
expect(user.role).to eq 'admin'
|
||||
end
|
||||
|
||||
it 'returns moderator for moderator' do
|
||||
user = User.new(moderator: true)
|
||||
expect(user.role).to eq 'moderator'
|
||||
end
|
||||
|
||||
it 'returns user otherwise' do
|
||||
user = User.new
|
||||
expect(user.role).to eq 'user'
|
||||
end
|
||||
end
|
||||
|
||||
describe '#role?' do
|
||||
it 'returns false when invalid role requested' do
|
||||
user = User.new(admin: true)
|
||||
expect(user.role?('disabled')).to be false
|
||||
end
|
||||
|
||||
it 'returns true when exact role match' do
|
||||
user = User.new
|
||||
mod = User.new(moderator: true)
|
||||
admin = User.new(admin: true)
|
||||
|
||||
expect(user.role?('user')).to be true
|
||||
expect(mod.role?('moderator')).to be true
|
||||
expect(admin.role?('admin')).to be true
|
||||
end
|
||||
|
||||
it 'returns true when role higher than needed' do
|
||||
mod = User.new(moderator: true)
|
||||
admin = User.new(admin: true)
|
||||
|
||||
expect(mod.role?('user')).to be true
|
||||
expect(admin.role?('user')).to be true
|
||||
expect(admin.role?('moderator')).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#disable!' do
|
||||
subject(:user) { Fabricate(:user, disabled: false, current_sign_in_at: current_sign_in_at, last_sign_in_at: nil) }
|
||||
let(:current_sign_in_at) { Time.zone.now }
|
||||
|
@ -420,110 +369,6 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#promote!' do
|
||||
subject(:user) { Fabricate(:user, admin: is_admin, moderator: is_moderator) }
|
||||
|
||||
before do
|
||||
user.promote!
|
||||
end
|
||||
|
||||
context 'when user is an admin' do
|
||||
let(:is_admin) { true }
|
||||
|
||||
context 'when user is a moderator' do
|
||||
let(:is_moderator) { true }
|
||||
|
||||
it 'changes moderator filed false' do
|
||||
expect(user).to be_admin
|
||||
expect(user).not_to be_moderator
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not a moderator' do
|
||||
let(:is_moderator) { false }
|
||||
|
||||
it 'does not change status' do
|
||||
expect(user).to be_admin
|
||||
expect(user).not_to be_moderator
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not admin' do
|
||||
let(:is_admin) { false }
|
||||
|
||||
context 'when user is a moderator' do
|
||||
let(:is_moderator) { true }
|
||||
|
||||
it 'changes user into an admin' do
|
||||
expect(user).to be_admin
|
||||
expect(user).not_to be_moderator
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not a moderator' do
|
||||
let(:is_moderator) { false }
|
||||
|
||||
it 'changes user into a moderator' do
|
||||
expect(user).not_to be_admin
|
||||
expect(user).to be_moderator
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#demote!' do
|
||||
subject(:user) { Fabricate(:user, admin: admin, moderator: moderator) }
|
||||
|
||||
before do
|
||||
user.demote!
|
||||
end
|
||||
|
||||
context 'when user is an admin' do
|
||||
let(:admin) { true }
|
||||
|
||||
context 'when user is a moderator' do
|
||||
let(:moderator) { true }
|
||||
|
||||
it 'changes user into a moderator' do
|
||||
expect(user).not_to be_admin
|
||||
expect(user).to be_moderator
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not a moderator' do
|
||||
let(:moderator) { false }
|
||||
|
||||
it 'changes user into a moderator' do
|
||||
expect(user).not_to be_admin
|
||||
expect(user).to be_moderator
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not an admin' do
|
||||
let(:admin) { false }
|
||||
|
||||
context 'when user is a moderator' do
|
||||
let(:moderator) { true }
|
||||
|
||||
it 'changes user into a plain user' do
|
||||
expect(user).not_to be_admin
|
||||
expect(user).not_to be_moderator
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not a moderator' do
|
||||
let(:moderator) { false }
|
||||
|
||||
it 'does not change any fields' do
|
||||
expect(user).not_to be_admin
|
||||
expect(user).not_to be_moderator
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active_for_authentication?' do
|
||||
subject { user.active_for_authentication? }
|
||||
let(:user) { Fabricate(:user, disabled: disabled, confirmed_at: confirmed_at) }
|
||||
|
@ -560,4 +405,8 @@ RSpec.describe User, type: :model do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '.those_who_can' do
|
||||
pending
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe AccountModerationNotePolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :create? do
|
||||
|
@ -31,7 +31,7 @@ RSpec.describe AccountModerationNotePolicy do
|
|||
|
||||
context 'admin' do
|
||||
it 'grants to destroy' do
|
||||
expect(subject).to permit(admin, AccountModerationNotePolicy)
|
||||
expect(subject).to permit(admin, account_moderation_note)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe AccountPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
let(:alice) { Fabricate(:account) }
|
||||
|
||||
|
@ -55,7 +55,7 @@ RSpec.describe AccountPolicy do
|
|||
end
|
||||
end
|
||||
|
||||
permissions :redownload?, :subscribe?, :unsubscribe? do
|
||||
permissions :redownload? do
|
||||
context 'admin' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin)
|
||||
|
@ -70,7 +70,7 @@ RSpec.describe AccountPolicy do
|
|||
end
|
||||
|
||||
permissions :suspend?, :silence? do
|
||||
let(:staff) { Fabricate(:user, admin: true).account }
|
||||
let(:staff) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
|
||||
context 'staff' do
|
||||
context 'record is staff' do
|
||||
|
@ -94,7 +94,7 @@ RSpec.describe AccountPolicy do
|
|||
end
|
||||
|
||||
permissions :memorialize? do
|
||||
let(:other_admin) { Fabricate(:user, admin: true).account }
|
||||
let(:other_admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
|
||||
context 'admin' do
|
||||
context 'record is admin' do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe CustomEmojiPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :enable?, :disable? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe DomainBlockPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :show?, :create?, :destroy? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe EmailDomainBlockPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :create?, :destroy? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe InstancePolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :show?, :destroy? do
|
||||
|
|
|
@ -5,8 +5,8 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe InvitePolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:user).account }
|
||||
|
||||
permissions :index? do
|
||||
context 'staff?' do
|
||||
|
@ -17,16 +17,22 @@ RSpec.describe InvitePolicy do
|
|||
end
|
||||
|
||||
permissions :create? do
|
||||
context 'min_required_role?' do
|
||||
context 'has privilege' do
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole::FLAGS[:invite_users])
|
||||
end
|
||||
|
||||
it 'permits' do
|
||||
allow_any_instance_of(described_class).to receive(:min_required_role?) { true }
|
||||
expect(subject).to permit(john, Invite)
|
||||
end
|
||||
end
|
||||
|
||||
context 'not min_required_role?' do
|
||||
context 'does not have privilege' do
|
||||
before do
|
||||
UserRole.everyone.update(permissions: UserRole::Flags::NONE)
|
||||
end
|
||||
|
||||
it 'denies' do
|
||||
allow_any_instance_of(described_class).to receive(:min_required_role?) { false }
|
||||
expect(subject).to_not permit(john, Invite)
|
||||
end
|
||||
end
|
||||
|
@ -54,39 +60,15 @@ RSpec.describe InvitePolicy do
|
|||
end
|
||||
|
||||
context 'not owner?' do
|
||||
context 'Setting.min_invite_role == "admin"' do
|
||||
before do
|
||||
Setting.min_invite_role = 'admin'
|
||||
end
|
||||
|
||||
context 'admin?' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin, Fabricate(:invite))
|
||||
end
|
||||
end
|
||||
|
||||
context 'not admin?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john, Fabricate(:invite))
|
||||
end
|
||||
context 'admin?' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin, Fabricate(:invite))
|
||||
end
|
||||
end
|
||||
|
||||
context 'Setting.min_invite_role != "admin"' do
|
||||
before do
|
||||
Setting.min_invite_role = 'else'
|
||||
end
|
||||
|
||||
context 'staff?' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin, Fabricate(:invite))
|
||||
end
|
||||
end
|
||||
|
||||
context 'not staff?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john, Fabricate(:invite))
|
||||
end
|
||||
context 'not admin?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john, Fabricate(:invite))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe RelayPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :update? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe ReportNotePolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :create? do
|
||||
|
@ -25,7 +25,8 @@ RSpec.describe ReportNotePolicy do
|
|||
permissions :destroy? do
|
||||
context 'admin?' do
|
||||
it 'permit' do
|
||||
expect(subject).to permit(admin, ReportNote)
|
||||
report_note = Fabricate(:report_note, account: john)
|
||||
expect(subject).to permit(admin, report_note)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe ReportPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :update?, :index?, :show? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe SettingsPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :update?, :show? do
|
||||
|
|
|
@ -6,7 +6,7 @@ require 'pundit/rspec'
|
|||
RSpec.describe StatusPolicy, type: :model do
|
||||
subject { described_class }
|
||||
|
||||
let(:admin) { Fabricate(:user, admin: true) }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')) }
|
||||
let(:alice) { Fabricate(:account, username: 'alice') }
|
||||
let(:bob) { Fabricate(:account, username: 'bob') }
|
||||
let(:status) { Fabricate(:status, account: alice) }
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe TagPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :index?, :show?, :update? do
|
||||
|
|
|
@ -5,7 +5,7 @@ require 'pundit/rspec'
|
|||
|
||||
RSpec.describe UserPolicy do
|
||||
let(:subject) { described_class }
|
||||
let(:admin) { Fabricate(:user, admin: true).account }
|
||||
let(:admin) { Fabricate(:user, role: UserRole.find_by(name: 'Admin')).account }
|
||||
let(:john) { Fabricate(:account) }
|
||||
|
||||
permissions :reset_password?, :change_email? do
|
||||
|
@ -111,57 +111,4 @@ RSpec.describe UserPolicy do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :promote? do
|
||||
context 'admin?' do
|
||||
context 'promotable?' do
|
||||
it 'permits' do
|
||||
expect(subject).to permit(admin, john.user)
|
||||
end
|
||||
end
|
||||
|
||||
context '!promotable?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(admin, admin.user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '!admin?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john, User)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
permissions :demote? do
|
||||
context 'admin?' do
|
||||
context '!record.admin?' do
|
||||
context 'demoteable?' do
|
||||
it 'permits' do
|
||||
john.user.update(moderator: true)
|
||||
expect(subject).to permit(admin, john.user)
|
||||
end
|
||||
end
|
||||
|
||||
context '!demoteable?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(admin, john.user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'record.admin?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(admin, admin.user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '!admin?' do
|
||||
it 'denies' do
|
||||
expect(subject).to_not permit(john, User)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue