diff --git a/app/controllers/admin/pending_accounts_controller.rb b/app/controllers/admin/pending_accounts_controller.rb new file mode 100644 index 000000000..8429d3585 --- /dev/null +++ b/app/controllers/admin/pending_accounts_controller.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Admin + class PendingAccountsController < BaseController + before_action :set_accounts, only: :index + + def index + @form = Form::AccountBatch.new + end + + def update + @form = Form::AccountBatch.new(form_account_batch_params.merge(current_account: current_account, action: action_from_button)) + @form.save + rescue ActionController::ParameterMissing + # Do nothing + ensure + redirect_to admin_pending_accounts_path(current_params) + end + + def approve_all + Form::AccountBatch.new(account_ids: User.pending.pluck(:account_id), action: 'approve').save + redirect_to admin_pending_accounts_path(current_params) + end + + def reject_all + Form::AccountBatch.new(account_ids: User.pending.pluck(:account_id), action: 'reject').save + redirect_to admin_pending_accounts_path(current_params) + end + + private + + def set_accounts + @accounts = Account.joins(:user).merge(User.pending).page(params[:page]) + end + + def form_account_batch_params + params.require(:form_account_batch).permit(:action, account_ids: []) + end + + def action_from_button + if params[:approve] + 'approve' + elsif params[:reject] + 'reject' + end + end + + def current_params + params.slice(:page).permit(:page) + end + end +end diff --git a/app/models/form/account_batch.rb b/app/models/form/account_batch.rb index 60eaaf0e2..5bc44e809 100644 --- a/app/models/form/account_batch.rb +++ b/app/models/form/account_batch.rb @@ -2,6 +2,7 @@ class Form::AccountBatch include ActiveModel::Model + include Authorization attr_accessor :account_ids, :action, :current_account @@ -13,6 +14,10 @@ class Form::AccountBatch remove_from_followers! when 'block_domains' block_domains! + when 'approve' + approve! + when 'reject' + reject! end end @@ -57,4 +62,18 @@ class Form::AccountBatch ActivityPub::DeliveryWorker.perform_async(json, current_account.id, follow.account.inbox_url) end + + def approve! + users = accounts.includes(:user).map(&:user) + + users.each { |user| authorize(user, :approve?) } + .each(&:approve!) + end + + def reject! + records = accounts.includes(:user) + + records.each { |account| authorize(account.user, :reject?) } + .each { |account| SuspendAccountService.new.call(account, including_user: true, destroy: true, skip_distribution: true) } + end end diff --git a/app/views/admin/accounts/index.html.haml b/app/views/admin/accounts/index.html.haml index 66808add7..7e9adb3ff 100644 --- a/app/views/admin/accounts/index.html.haml +++ b/app/views/admin/accounts/index.html.haml @@ -10,7 +10,7 @@ .filter-subset %strong= t('admin.accounts.moderation.title') %ul - %li= filter_link_to t('admin.accounts.moderation.pending'), pending: '1', silenced: nil, suspended: nil + %li= link_to safe_join([t('admin.accounts.moderation.pending'), "(#{number_with_delimiter(User.pending.count)})"], ' '), admin_pending_accounts_path %li= filter_link_to t('admin.accounts.moderation.active'), silenced: nil, suspended: nil, pending: nil %li= filter_link_to t('admin.accounts.moderation.silenced'), silenced: '1', suspended: nil, pending: nil %li= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1', silenced: nil, pending: nil diff --git a/app/views/admin/pending_accounts/_account.html.haml b/app/views/admin/pending_accounts/_account.html.haml new file mode 100644 index 000000000..c520dc065 --- /dev/null +++ b/app/views/admin/pending_accounts/_account.html.haml @@ -0,0 +1,14 @@ +.batch-table__row + %label.batch-table__row__select.batch-table__row__select--aligned.batch-checkbox + = f.check_box :account_ids, { multiple: true, include_hidden: false }, account.id + .batch-table__row__content.batch-table__row__content--unpadded + %table.accounts-table + %tbody + %tr + %td + = account.user_email + = "(@#{account.username})" + %br/ + = account.user_current_sign_in_ip + %td.accounts-table__count + = table_link_to 'pencil', t('admin.accounts.edit'), admin_account_path(account.id) diff --git a/app/views/admin/pending_accounts/index.html.haml b/app/views/admin/pending_accounts/index.html.haml new file mode 100644 index 000000000..77b96cbca --- /dev/null +++ b/app/views/admin/pending_accounts/index.html.haml @@ -0,0 +1,33 @@ +- content_for :page_title do + = t('admin.pending_accounts.title', count: User.pending.count) + +- content_for :header_tags do + = javascript_pack_tag 'admin', integrity: true, async: true, crossorigin: 'anonymous' + += form_for(@form, url: admin_pending_accounts_path, method: :patch) do |f| + = hidden_field_tag :page, params[:page] || 1 + + .batch-table + .batch-table__toolbar + %label.batch-table__toolbar__select.batch-checkbox-all + = check_box_tag :batch_checkbox_all, nil, false + .batch-table__toolbar__actions + = f.button safe_join([fa_icon('check'), t('admin.accounts.approve')]), name: :approve, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + + = f.button safe_join([fa_icon('times'), t('admin.accounts.reject')]), name: :reject, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } + .batch-table__body + - if @accounts.empty? + = nothing_here 'nothing-here--under-tabs' + - else + = render partial: 'account', collection: @accounts, locals: { f: f } + += paginate @accounts + +%hr.spacer/ + +%div{ style: 'overflow: hidden' } + %div{ style: 'float: right' } + = link_to t('admin.accounts.reject_all'), reject_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button button--destructive' + + %div + = link_to t('admin.accounts.approve_all'), approve_all_admin_pending_accounts_path, method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' diff --git a/config/locales/en.yml b/config/locales/en.yml index 705024ff5..df9c4913c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -330,6 +330,8 @@ en: expired: Expired title: Filter title: Invites + pending_accounts: + title: Pending accounts (%{count}) relays: add_new: Add new relay delete: Delete @@ -496,7 +498,7 @@ en: salutation: "%{name}," settings: 'Change e-mail preferences: %{link}' view: 'View:' - view_profile: View Profile + view_profile: View profile view_status: View status applications: created: Application successfully created diff --git a/config/navigation.rb b/config/navigation.rb index a6b2b6e4c..dd5825867 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -28,7 +28,7 @@ SimpleNavigation::Configuration.run do |navigation| primary.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), admin_reports_url, if: proc { current_user.staff? } do |admin| admin.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_url admin.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_url, highlights_on: %r{/admin/reports} - admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts} + admin.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_url, highlights_on: %r{/admin/accounts|/admin/pending_accounts} admin.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path admin.item :tags, safe_join([fa_icon('tag fw'), t('admin.tags.title')]), admin_tags_path admin.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_url(limited: '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks}, if: -> { current_user.admin? } diff --git a/config/routes.rb b/config/routes.rb index a98dbb700..1ea6490b0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -214,6 +214,13 @@ Rails.application.routes.draw do end end + resources :pending_accounts, only: [:index, :update] do + collection do + post :approve_all + post :reject_all + end + end + resources :users, only: [] do resource :two_factor_authentication, only: [:destroy] end