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
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 private
def handle_organization_tab def handle_organization_tab

View file

@ -1,5 +1,6 @@
import { initBlock } from '../profileDropdown/blockButton'; import { initBlock } from '../profileDropdown/blockButton';
import { initFlag } from '../profileDropdown/flagButton'; import { initFlag } from '../profileDropdown/flagButton';
import { initSpam } from '../profileDropdown/spamButton';
import { initializeDropdown } from '@utilities/dropdownUtils'; import { initializeDropdown } from '@utilities/dropdownUtils';
/* global userData */ /* global userData */
@ -7,6 +8,7 @@ import { initializeDropdown } from '@utilities/dropdownUtils';
function initButtons() { function initButtons() {
initBlock(); initBlock();
initFlag(); initFlag();
initSpam();
} }
function initDropdown() { 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 manage_user_roles? elevated_user?
alias unpublish_all_articles? elevated_user? alias unpublish_all_articles? elevated_user?
alias search_by_email? elevated_user? alias search_by_email? elevated_user?
alias toggle_spam? elevated_user?
def moderation_routes? def moderation_routes?
(user.has_trusted_role? || elevated_user?) && !user.spam_or_suspended? (user.has_trusted_role? || elevated_user?) && !user.spam_or_suspended?

View file

@ -50,6 +50,15 @@
class="border-none crayons-link crayons-link--block"> class="border-none crayons-link crayons-link--block">
<%= t("views.users.#{@flag_status ? 'unflag' : 'flag'}", user: @user.username) %> <%= t("views.users.#{@flag_status ? 'unflag' : 'flag'}", user: @user.username) %>
</a> </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 %> <% end %>
<span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= user_url(@user) %>"></span> <span class="report-abuse-link-wrapper" data-path="/report-abuse?url=<%= user_url(@user) %>"></span>
</div> </div>

View file

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

View file

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

View file

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