Add mark as spam button on user profile for admins (#20794)

This commit is contained in:
Philip How 2024-03-25 14:30:16 +00:00 committed by GitHub
parent 6b8c363487
commit b0086c9171
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 121 additions and 0 deletions

View file

@ -266,6 +266,37 @@ class UsersController < ApplicationController
end
end
def toggle_spam
@target_user = User.find_by(id: params[:id])
render json, status: :not_found unless @target_user
authorize @current_user
begin
case request.method_symbol
when :put
manager = Moderator::ManageActivityAndRoles.new(admin: @current_user, user: @target_user, user_params: {})
manager.handle_user_status("Spam", "Mark as Spam from user profile")
payload = { action: "mark_as_spam", target_user_id: params[:id] }
Audit::Logger.log(:admin, @current_user, payload)
when :delete
manager = Moderator::ManageActivityAndRoles.new(admin: @current_user, user: @target_user, user_params: {})
manager.handle_user_status("Good standing", "Set in good standing from user profile")
payload = { action: "remove_spam_role_from_user", target_user_id: params[:id] }
Audit::Logger.log(:admin, @current_user, payload)
else
render json, status: :method_not_allowed
end
head :no_content
rescue StandardError => e
Rails.logger.error("Failed to toggle spam status for user #{params[:id]}: #{e.message}")
respond_to do |format|
format.html { redirect_to "/dashboard", notice: I18n.t("articles_controller.deleted") }
format.json { head :internal_server_error }
end
end
end
private
def handle_organization_tab

View file

@ -1,5 +1,6 @@
import { initBlock } from '../profileDropdown/blockButton';
import { initFlag } from '../profileDropdown/flagButton';
import { initSpam } from '../profileDropdown/spamButton';
import { initializeDropdown } from '@utilities/dropdownUtils';
/* global userData */
@ -7,6 +8,7 @@ import { initializeDropdown } from '@utilities/dropdownUtils';
function initButtons() {
initBlock();
initFlag();
initSpam();
}
function initDropdown() {

View file

@ -0,0 +1,66 @@
/* global userData */
/* eslint-disable no-alert, import/order */
import { request } from '@utilities/http';
import { getUserDataAndCsrfToken } from '@utilities/getUserDataAndCsrfToken';
function addSpamButton(spamButton) {
const { profileUserId, profileUserName } = spamButton.dataset;
let isUserSpam = spamButton.dataset.isUserSpam === 'true';
function toggleSpam() {
const confirm = window.confirm(
isUserSpam
? 'Are you sure you want to remove the spam role from this user? This will make all of their posts and comments visible again, and regain their access to new posts'
: 'Are you sure you want to add the spam role to this user? This will hide all of their posts and comments and restrict their access to create new posts and comments',
);
if (confirm) {
request(`/users/${profileUserId}/spam`, {
method: isUserSpam ? 'DELETE' : 'PUT',
})
.then((response) => {
if (response.ok) {
isUserSpam = !isUserSpam;
spamButton.innerHTML = isUserSpam ? `Set ${profileUserName} in Good standing` : `Mark ${profileUserName} as Spam`;
}
})
.catch((e) => {
Honeybadger.notify(
isUserSpam ? 'Unable to remove spam role from user' : 'Unable to mark user as spam',
profileUserId,
);
window.alert(`Something went wrong: ${e}`);
});
}
}
spamButton.addEventListener('click', toggleSpam);
}
/**
* Adds a spam button visible only to admin users on profile pages.
* @function initSpam
* @returns {(void|undefined)} This function has no useable return value.
*/
export function initSpam() {
const spamButton = document.getElementById(
'user-profile-dropdownmenu-spam-button',
);
if (!spamButton) {
// button not always present when this is called
return;
}
getUserDataAndCsrfToken().then(() => {
const user = userData();
if (!user || !user.admin) {
spamButton.remove();
return;
}
addSpamButton(spamButton);
});
}
/* eslint-enable no-alert */

View file

@ -97,6 +97,7 @@ class UserPolicy < ApplicationPolicy
alias manage_user_roles? elevated_user?
alias unpublish_all_articles? elevated_user?
alias search_by_email? elevated_user?
alias toggle_spam? elevated_user?
def moderation_routes?
(user.has_trusted_role? || elevated_user?) && !user.spam_or_suspended?

View file

@ -50,6 +50,15 @@
class="border-none crayons-link crayons-link--block">
<%= t("views.users.#{@flag_status ? 'unflag' : 'flag'}", user: @user.username) %>
</a>
<a
href="javascript:void(0);"
id="user-profile-dropdownmenu-spam-button"
data-profile-user-id="<%= @user.id %>"
data-profile-user-name="@<%= @user.username %>"
data-is-user-spam="<%= @user.spam? %>"
class="border-none crayons-link crayons-link--block">
<%= t("views.users.#{@user.spam? ? 'unspam' : 'spam'}", user: @user.username) %>
</a>
<% end %>
<span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= user_url(@user) %>"></span>
</div>

View file

@ -91,6 +91,8 @@ en:
notice_html: All private interactions <b>must</b> abide by the %{code}.
placeholder: Enter your message here...
submit: Send
spam: Mark @%{user} as Spam
social: "%{service} website"
unflag: Unflag @%{user}
unspam: Set @%{user} in Good standing
website: Personal website

View file

@ -92,5 +92,7 @@ fr:
placeholder: Enter your message here...
submit: Send
social: "%{service} website"
spam: Marquer @%{user} comme spam
unflag: Unflag @%{user}
unspam: Définir @%{user} en règle
website: Personal website

View file

@ -117,6 +117,10 @@ Rails.application.routes.draw do
end
resources :comment_mutes, only: %i[update]
resources :users, only: %i[index show], defaults: { format: :json } do # internal API
member do
put "spam", to: "users#toggle_spam"
delete "spam", to: "users#toggle_spam"
end
collection do
resources :devices, only: %i[create destroy]
end
@ -247,6 +251,10 @@ Rails.application.routes.draw do
delete "users/api_secrets/:id", to: "api_secrets#destroy", as: :users_api_secret
post "users/update_password", to: "users#update_password", as: :user_update_password
# Internal Admin API
# put "/users/:id/spam", to: "users#toggle_spam", as: :user_toggle_spam
# delete "/users/:id/spam", to: "users#toggle_spam", as: :user_toggle_spam
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".