From 750d379807367b404fbb00bfe3509d6063db03a8 Mon Sep 17 00:00:00 2001 From: Arit Amana <32520970+msarit@users.noreply.github.com> Date: Mon, 27 Jun 2022 12:45:35 -0400 Subject: [PATCH] Allow ModRole & Admin to Suspend & Unsuspend User (#17946) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * gotta commit at some point * out of gas * IT'S WORKING NOW! đĨ * Cypress tests * fix Travis failures * incorporate PR review suggestions * fix one failing Cypress test * update API call * add Unsuspend flow; fix Travis failures * add tests for unsuspend flow * remove unnecessary atrribute * add article_policy spec * fix failing Travis * nudge Travis * fix apparent typo o o 𤡠* refactor a bunch of duplication * nudge Travis * fix Cypress failure related to authorizing moderator for user_status action * rename modal partial * remove unnecessary button-exists check * address PR review suggestions * hide suspend user btn after action * toggle btn based on author suspension status * add data-testids * use data-testids * controller refactor --- app/controllers/admin/users_controller.rb | 40 +++- app/javascript/actionsPanel/actionsPanel.js | 9 + .../components/Help/BasicEditor.jsx | 2 +- app/javascript/crayons/Modal/Modal.jsx | 2 + .../packs/admin/users/gdprDeleteRequests.jsx | 2 +- app/javascript/packs/base.jsx | 2 +- .../packs/toggleUserSuspensionModal.js | 144 +++++++++++++++ .../shared/components/focusTrap.jsx | 4 +- app/javascript/utilities/showModal.jsx | 5 +- app/policies/article_policy.rb | 9 +- app/policies/user_policy.rb | 9 +- app/views/articles/show.html.erb | 2 + .../moderations/_suspend_user_modal.html.erb | 41 +++++ .../_unsuspend_user_modal.html.erb | 41 +++++ app/views/moderations/actions_panel.html.erb | 23 ++- config/locales/controllers/admin/en.yml | 29 +-- config/locales/controllers/admin/fr.yml | 29 +-- config/locales/views/moderations/en.yml | 35 ++-- config/locales/views/moderations/fr.yml | 35 ++-- .../articleFlows/postModerationTools.spec.js | 171 +++++++++++++++++- spec/policies/article_policy_spec.rb | 2 +- spec/support/seeds/seeds_e2e.rb | 43 +++++ 22 files changed, 588 insertions(+), 91 deletions(-) create mode 100644 app/javascript/packs/toggleUserSuspensionModal.js create mode 100644 app/views/moderations/_suspend_user_modal.html.erb create mode 100644 app/views/moderations/_unsuspend_user_modal.html.erb diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 1b38381ce..1738481cf 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -29,6 +29,17 @@ module Admin Audit::Logger.log(:moderator, current_user, params.dup) end + # Having this method here (which also exists in admin/application_controller) + # allows us to authorize the moderator role specifically for the user_status + # action, while preserving the implementation for all other admin actions + def authorize_admin + if action_name == "user_status" + authorize(User, :toggle_suspension_status?) + else + super + end + end + def index @users = Admin::UsersQuery.call( relation: User.registered, @@ -104,18 +115,33 @@ module Admin begin Moderator::ManageActivityAndRoles.handle_user_roles(admin: current_user, user: @user, user_params: user_params) flash[:success] = I18n.t("admin.users_controller.updated") + respond_to do |format| + format.html do + redirect_back_or_to admin_users_path + end + format.json do + render json: { + success: true, + message: I18n.t("admin.users_controller.updated_json", username: @user.username) + }, status: :ok + end + end rescue StandardError => e flash[:danger] = e.message + respond_to do |format| + format.html do + redirect_back_or_to admin_users_path + end + format.json do + render json: { + success: false, + message: @user.errors_as_sentence + }, status: :unprocessable_entity + end + end end - Credits::Manage.call(@user, credit_params) add_note if user_params[:new_note] - - if request.referer&.include?(admin_user_path(params[:id])) - redirect_to admin_user_path(params[:id]) - else - redirect_to admin_users_path - end end def export_data diff --git a/app/javascript/actionsPanel/actionsPanel.js b/app/javascript/actionsPanel/actionsPanel.js index 1f37610a5..b40cda99d 100644 --- a/app/javascript/actionsPanel/actionsPanel.js +++ b/app/javascript/actionsPanel/actionsPanel.js @@ -1,4 +1,5 @@ import { toggleFlagUserModal } from '../packs/flagUserModal'; +import { toggleModal } from '../packs/toggleUserSuspensionModal'; import { toggleUnpublishPostModal } from '../packs/unpublishPostModal'; import { request } from '@utilities/http'; @@ -395,6 +396,14 @@ export function addBottomActionsListeners() { document .getElementById('open-flag-user-modal') .addEventListener('click', toggleFlagUserModal); + + document + .getElementById('suspend-user-btn') + ?.addEventListener('click', toggleModal); + + document + .getElementById('unsuspend-user-btn') + ?.addEventListener('click', toggleModal); } export function initializeActionsPanel() { diff --git a/app/javascript/article-form/components/Help/BasicEditor.jsx b/app/javascript/article-form/components/Help/BasicEditor.jsx index a25ece38e..da47dd8be 100644 --- a/app/javascript/article-form/components/Help/BasicEditor.jsx +++ b/app/javascript/article-form/components/Help/BasicEditor.jsx @@ -31,5 +31,5 @@ export const BasicEditor = ({ openModal }) => ( ); BasicEditor.propTypes = { - toggleModal: PropTypes.func.isRequired, + openModal: PropTypes.func.isRequired, }; diff --git a/app/javascript/crayons/Modal/Modal.jsx b/app/javascript/crayons/Modal/Modal.jsx index b26d710a4..9da5e2145 100644 --- a/app/javascript/crayons/Modal/Modal.jsx +++ b/app/javascript/crayons/Modal/Modal.jsx @@ -20,6 +20,7 @@ export const Modal = ({ backdropDismissible = false, onClose = () => {}, focusTrapSelector = '.crayons-modal__box', + document = window.document, }) => { const classes = classNames('crayons-modal', { [`crayons-modal--${size}`]: size && size !== 'medium', @@ -36,6 +37,7 @@ export const Modal = ({ onDeactivate={onClose} clickOutsideDeactivates={backdropDismissible} selector={focusTrapSelector} + document={document} >
+ <%= t("views.moderations.actions.suspend.suspend_modal_text", username: author_username) %> +
+ ++
++ <%= t("views.moderations.actions.suspend.unsuspend_modal_text", username: author_username) %> +
+ ++
+