Add or remove limited role via API (#20136)

* Refactor API user suspend, make room for more roles

* Handle adding limited

* Handle remove limited

* And swagger docs

* Update & refactor roles spec

* Remove old route

* Remove old specs
This commit is contained in:
Joshua Wehner 2023-09-26 15:57:14 +02:00 committed by GitHub
parent e5b4f6a7d0
commit 2c138d86ef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 1205 additions and 686 deletions

View file

@ -0,0 +1,99 @@
module Api
module V1
class UserRolesController < ApiController
before_action :authenticate_with_api_key!
# 'suspended' is also known as 'suspend' for historical reasons
SUSPEND_MODE = %w[suspend suspended].freeze
ROLES = (SUSPEND_MODE + %w[limited]).freeze
before_action :check_role
before_action :set_target_user
before_action :authorize_role_management
rescue_from StandardError, with: :unprocessable_error
def update
if suspend_mode? # suspend user requires more data, such as note
suspend_target_user
else
add_role_to_target_user
end
render json: { success: "okay" }, status: :no_content
end
def destroy
# This mechanism for removing roles is pretty specific to limited & suspended,
# where they revert to "Good standing" — we would need a different approach,
# possibly a whole different service object — to remove *any* roles
remove_role_from_target_user
render json: { success: "okay" }, status: :no_content
end
private
def add_role_to_target_user
manager = Moderator::ManageActivityAndRoles.new(admin: @user,
user: @target_user,
user_params: {})
manager.handle_user_status(params[:role].titleize, nil)
payload = { action: "api_user_#{params[:role]}", target_user_id: @target_user.id }
Audit::Logger.log(:admin_api, @user, payload)
end
def authorize_role_management
authorize(@target_user, :manage_user_roles?)
rescue Pundit::NotAuthorizedError
error_unauthorized
end
def check_role
return if ROLES.include?(params[:role])
raise StandardError, "Unable to process #{params[:role]}"
end
def remove_role_from_target_user
manager = Moderator::ManageActivityAndRoles.new(admin: @user,
user: @target_user,
user_params: {})
manager.handle_user_status("Good standing", nil)
payload = { action: "api_user_remove_#{params[:role]}", target_user_id: @target_user.id }
Audit::Logger.log(:admin_api, @user, payload)
end
def set_target_user
@target_user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
error_not_found
end
def suspend_mode?
SUSPEND_MODE.include?(params[:role])
end
def suspend_target_user
suspend_params = { note_for_current_role: params[:note], user_status: "Suspended" }
Moderator::ManageActivityAndRoles.handle_user_roles(admin: @user,
user: @target_user,
user_params: suspend_params)
payload = { action: "api_user_suspend", target_user_id: @target_user.id }
Audit::Logger.log(:admin_api, @user, payload)
end
def unprocessable_error(exception)
message = @target_user&.errors_as_sentence || exception.message
render json: {
success: false,
message: message
}, status: :unprocessable_entity
end
end
end
end

View file

@ -22,29 +22,6 @@ module Api
render :show
end
def suspend
authorize(@user, :toggle_suspension_status?)
target_user = User.find(params[:id])
suspend_params = { note_for_current_role: params[:note], user_status: "Suspended" }
begin
Moderator::ManageActivityAndRoles.handle_user_roles(admin: @user,
user: target_user,
user_params: suspend_params)
payload = { action: "api_user_suspend", target_user_id: target_user.id }
Audit::Logger.log(:admin_api, @user, payload)
render status: :no_content
rescue StandardError
render json: {
success: false,
message: @user.errors_as_sentence
}, status: :unprocessable_entity
end
end
def unpublish
authorize(@user, :unpublish_all_articles?)

View file

@ -94,6 +94,7 @@ class UserPolicy < ApplicationPolicy
end
alias toggle_suspension_status? elevated_user?
alias manage_user_roles? elevated_user?
alias unpublish_all_articles? elevated_user?
def moderation_routes?

View file

@ -135,6 +135,7 @@ module Moderator
end
def remove_negative_roles
user.remove_role(:limited) if user.limited?
user.remove_role(:suspended) if user.suspended?
user.remove_role(:warned) if user.warned?
user.remove_role(:comment_suspended) if user.comment_suspended?

View file

@ -44,7 +44,6 @@ Rails.application.routes.draw do
namespace :api, defaults: { format: "json" } do
scope module: :v1, constraints: ApiConstraints.new(version: 1, default: false) do
# V1 only endpoints
put "/users/:id/suspend", to: "users#suspend", as: :user_suspend
put "/articles/:id/unpublish", to: "articles#unpublish", as: :article_unpublish
put "/users/:id/unpublish", to: "users#unpublish", as: :user_unpublish
@ -69,6 +68,16 @@ Rails.application.routes.draw do
resources :organizations, only: %i[index create update destroy]
scope("/users/:id") do
constraints(role: /suspend|suspended|limited/) do
put "/:role", to: "user_roles#update", as: "user_add_role"
end
constraints(role: /limited/) do
delete "/:role", to: "user_roles#destroy", as: "user_remove_role"
end
end
draw :api
end

View file

@ -0,0 +1,188 @@
require "rails_helper"
require "swagger_helper"
# rubocop:disable RSpec/EmptyExampleGroup
# rubocop:disable RSpec/VariableName
RSpec.describe "Api::V1::Docs::Users" do
let(:Accept) { "application/vnd.forem.api-v1+json" }
let(:api_secret) { create(:api_secret) }
let(:user) { api_secret.user }
let(:banned_user) { create(:user) }
let(:article) { create(:article, user: banned_user, published: true) }
let(:comment) { create(:comment, user: banned_user, article: article) }
before do
user.add_role(:admin)
end
describe "PUT /users/:id/suspend" do
before do
user.add_role(:admin)
end
path "/api/users/{id}/suspend" do
put "Suspend a User" do
tags "users"
description "This endpoint allows the client to suspend a user.
The user associated with the API key must have any 'admin' or 'moderator' role.
This specified user will be assigned the 'suspended' role. Suspending a user will stop the
user from posting new posts and comments. It doesn't delete any of the user's content, just
prevents them from creating new content while suspended. Users are not notified of their suspension
in the UI, so if you want them to know about this, you must notify them."
operationId "suspendUser"
produces "application/json"
parameter name: :id, in: :path, required: true,
description: "The ID of the user to suspend.",
schema: {
type: :integer,
format: :int32,
minimum: 1
},
example: 1
response "204", "User successfully unpublished" do
let(:"api-key") { api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "401", "Unauthorized" do
let(:regular_user) { create(:user) }
let(:low_security_api_secret) { create(:api_secret, user: regular_user) }
let(:"api-key") { low_security_api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "404", "Unknown User ID" do
let(:"api-key") { api_secret.secret }
let(:id) { 10_000 }
add_examples
run_test!
end
end
end
end
describe "PUT /users/:id/limited" do
before do
user.add_role(:admin)
end
path "/api/users/{id}/limited" do
put "Add limited role for a User" do
tags "users"
description "This endpoint allows the client to limit a user.
The user associated with the API key must have any 'admin' or 'moderator' role.
This specified user will be assigned the 'limited' role. Limiting a user will limit notifications
generated from new posts and comments. It doesn't delete any of the user's content or prevent them
from generating new content while limited. Users are not notified of their limits
in the UI, so if you want them to know about this, you must notify them."
operationId "limitUser"
produces "application/json"
parameter name: :id, in: :path, required: true,
description: "The ID of the user to limit.",
schema: {
type: :integer,
format: :int32,
minimum: 1
},
example: 1
response "204", "User successfully limited" do
let(:"api-key") { api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "401", "Unauthorized" do
let(:regular_user) { create(:user) }
let(:low_security_api_secret) { create(:api_secret, user: regular_user) }
let(:"api-key") { low_security_api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "404", "Unknown User ID" do
let(:"api-key") { api_secret.secret }
let(:id) { 10_000 }
add_examples
run_test!
end
end
end
end
describe "DELETE /users/:id/limited" do
before do
user.add_role(:admin)
end
path "/api/users/{id}/limited" do
delete "Remove limited for a User" do
tags "users"
description "This endpoint allows the client to remove limits for a user.
The user associated with the API key must have any 'admin' or 'moderator' role.
This specified user will be restored to 'general' status. Users are not notified
of limits in the UI, so if you want them to know about this, you must
notify them."
operationId "unLimitUser"
produces "application/json"
parameter name: :id, in: :path, required: true,
description: "The ID of the user to un-limit.",
schema: {
type: :integer,
format: :int32,
minimum: 1
},
example: 1
response "204", "User successfully un-limited" do
let(:"api-key") { api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "401", "Unauthorized" do
let(:regular_user) { create(:user) }
let(:low_security_api_secret) { create(:api_secret, user: regular_user) }
let(:"api-key") { low_security_api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "404", "Unknown User ID" do
let(:"api-key") { api_secret.secret }
let(:id) { 10_000 }
add_examples
run_test!
end
end
end
end
end
# rubocop:enable RSpec/VariableName
# rubocop:enable RSpec/EmptyExampleGroup

View file

@ -127,62 +127,6 @@ request is completed on the server."
end
end
describe "PUT /users/:id/suspend" do
before do
user.add_role(:admin)
end
path "/api/users/{id}/suspend" do
put "Suspend a User" do
tags "users"
description "This endpoint allows the client to suspend a user.
The user associated with the API key must have any 'admin' or 'moderator' role.
This specified user will be assigned the 'suspended' role. Suspending a user will stop the
user from posting new posts and comments. It doesn't delete any of the user's content, just
prevents them from creating new content while suspended. Users are not notified of their suspension
in the UI, so if you want them to know about this, you must notify them."
operationId "suspendUser"
produces "application/json"
parameter name: :id, in: :path, required: true,
description: "The ID of the user to suspend.",
schema: {
type: :integer,
format: :int32,
minimum: 1
},
example: 1
response "204", "User successfully unpublished" do
let(:"api-key") { api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "401", "Unauthorized" do
let(:regular_user) { create(:user) }
let(:low_security_api_secret) { create(:api_secret, user: regular_user) }
let(:"api-key") { low_security_api_secret.secret }
let(:id) { banned_user.id }
add_examples
run_test!
end
response "404", "Unknown User ID" do
let(:"api-key") { api_secret.secret }
let(:id) { 10_000 }
add_examples
run_test!
end
end
end
end
describe "POST /api/admin/users" do
before do
user.add_role(:super_admin)

View file

@ -0,0 +1,181 @@
require "rails_helper"
RSpec.describe "Api::V1::UserRoles" do
let(:api_secret) { create(:api_secret) }
let(:headers) { { "Accept" => "application/vnd.forem.api-v1+json" } }
let(:auth_headers) { headers.merge({ "api-key" => api_secret.secret }) }
let(:listener) { :admin_api }
describe "PUT /api/users/:id/suspend", :aggregate_failures do
let(:target_user) { create(:user) }
let(:payload) { { note: "Violated CoC despite multiple warnings" } }
before { Audit::Subscribe.listen listener }
after { Audit::Subscribe.forget listener }
context "when unauthenticated" do
it "returns unauthorized" do
put api_user_add_role_path(id: target_user.id, role: "suspended"),
params: payload,
headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when unauthorized" do
it "returns unauthorized if api key is invalid" do
put api_user_add_role_path(id: target_user.id, role: "suspended"),
params: payload,
headers: headers.merge({ "api-key" => "invalid api key" })
expect(response).to have_http_status(:unauthorized)
end
it "returns unauthorized if api key belongs to non-admin user" do
put api_user_add_role_path(id: target_user.id, role: "suspended"),
params: payload,
headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when request is authenticated" do
before { api_secret.user.add_role(:super_admin) }
it "is successful in suspending a user", :aggregate_failures do
expect do
put api_user_add_role_path(id: target_user.id, role: "suspended"),
params: payload,
headers: auth_headers
expect(response).to have_http_status(:no_content)
expect(target_user.reload.suspended?).to be true
expect(Note.last.content).to eq(payload[:note])
end.to change(Note, :count).by(1)
end
it "creates an audit log of the action taken" do
put api_user_add_role_path(id: target_user.id, role: "suspended"),
params: payload,
headers: auth_headers
log = AuditLog.last
expect(log.category).to eq(AuditLog::ADMIN_API_AUDIT_LOG_CATEGORY)
expect(log.data["action"]).to eq("api_user_suspend")
expect(log.data["target_user_id"]).to eq(target_user.id)
expect(log.user_id).to eq(api_secret.user.id)
end
end
end
describe "PUT /api/users/:id/limited", :aggregate_failures do
let(:target_user) { create(:user) }
before { Audit::Subscribe.listen listener }
after { Audit::Subscribe.forget listener }
context "when unauthenticated" do
it "returns unauthorized" do
put api_user_add_role_path(target_user, "limited"), headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when unauthorized" do
it "returns unauthorized if api key is invalid" do
put api_user_add_role_path(target_user, "limited"),
headers: headers.merge({ "api-key" => "invalid api key" })
expect(response).to have_http_status(:unauthorized)
end
# Setup via let(:api_secret) creates a user with no admin privileges
it "returns unauthorized if api key belongs to non-admin user" do
put api_user_add_role_path(target_user, "limited"), headers: auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when request is authenticated" do
before { api_secret.user.add_role(:super_admin) }
it "is successful in limiting a user", :aggregate_failures do
expect do
put api_user_add_role_path(target_user, "limited"), headers: auth_headers
expect(response).to have_http_status(:no_content)
expect(target_user.reload.limited?).to be true
expect(Note.last.content).to match(/username\d+ updated username\d+/)
end.to change(Note, :count).by(1)
end
it "creates an audit log of the action taken" do
put api_user_add_role_path(target_user, "limited"), headers: auth_headers
log = AuditLog.last
expect(log.category).to eq(AuditLog::ADMIN_API_AUDIT_LOG_CATEGORY)
expect(log.data["action"]).to eq("api_user_limited")
expect(log.data["target_user_id"]).to eq(target_user.id)
expect(log.user_id).to eq(api_secret.user.id)
end
end
end
describe "DELETE /api/users/:id/limited", :aggregate_failures do
let(:target_user) { create(:user, :limited) }
before { Audit::Subscribe.listen listener }
after { Audit::Subscribe.forget listener }
context "when unauthenticated" do
it "returns unauthorized" do
delete api_user_remove_role_path(target_user, "limited"), headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when unauthorized" do
it "returns unauthorized if api key is invalid" do
delete api_user_remove_role_path(target_user, "limited"),
headers: headers.merge({ "api-key" => "invalid api key" })
expect(response).to have_http_status(:unauthorized)
end
# Setup via let(:api_secret) creates a user with no admin privileges
it "returns unauthorized if api key belongs to non-admin user" do
delete api_user_remove_role_path(target_user, "limited"), headers: auth_headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when request is authenticated" do
before { api_secret.user.add_role(:super_admin) }
it "is successful in limiting a user", :aggregate_failures do
expect do
delete api_user_remove_role_path(target_user, "limited"), headers: auth_headers
expect(response).to have_http_status(:no_content)
expect(target_user.reload.limited?).to be false
expect(target_user.roles).to eq([])
expect(Note.last.content).to match(/username\d+ updated username\d+/)
end.to change(Note, :count).by(1)
end
it "creates an audit log of the action taken" do
delete api_user_remove_role_path(target_user, "limited"), headers: auth_headers
log = AuditLog.last
expect(log.category).to eq(AuditLog::ADMIN_API_AUDIT_LOG_CATEGORY)
expect(log.data["action"]).to eq("api_user_remove_limited")
expect(log.data["target_user_id"]).to eq(target_user.id)
expect(log.user_id).to eq(api_secret.user.id)
end
end
end
end

View file

@ -123,71 +123,6 @@ RSpec.describe "Api::V1::Users" do
end
end
describe "PUT /api/users/:id/suspend", :aggregate_failures do
let(:target_user) { create(:user) }
let(:payload) { { note: "Violated CoC despite multiple warnings" } }
before { Audit::Subscribe.listen listener }
after { Audit::Subscribe.forget listener }
context "when unauthenticated" do
it "returns unauthorized" do
put api_user_suspend_path(id: target_user.id),
params: payload,
headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when unauthorized" do
it "returns unauthorized if api key is invalid" do
put api_user_suspend_path(id: target_user.id),
params: payload,
headers: headers.merge({ "api-key" => "invalid api key" })
expect(response).to have_http_status(:unauthorized)
end
it "returns unauthorized if api key belongs to non-admin user" do
put api_user_suspend_path(id: target_user.id),
params: payload,
headers: headers
expect(response).to have_http_status(:unauthorized)
end
end
context "when request is authenticated" do
before { api_secret.user.add_role(:super_admin) }
it "is successful in suspending a user", :aggregate_failures do
expect do
put api_user_suspend_path(id: target_user.id),
params: payload,
headers: auth_headers
expect(response).to have_http_status(:no_content)
expect(target_user.reload.suspended?).to be true
expect(Note.last.content).to eq(payload[:note])
end.to change(Note, :count).by(1)
end
it "creates an audit log of the action taken" do
put api_user_suspend_path(id: target_user.id),
params: payload,
headers: auth_headers
log = AuditLog.last
expect(log.category).to eq(AuditLog::ADMIN_API_AUDIT_LOG_CATEGORY)
expect(log.data["action"]).to eq("api_user_suspend")
expect(log.data["target_user_id"]).to eq(target_user.id)
expect(log.user_id).to eq(api_secret.user.id)
end
end
end
describe "PUT /api/users/:id/unpublish", :aggregate_failures do
let(:target_user) { create(:user) }
let!(:target_articles) { create_list(:article, 3, user: target_user, published: true) }
@ -227,8 +162,8 @@ RSpec.describe "Api::V1::Users" do
it "is successful in unpublishing a user's comments and articles", :aggregate_failures do
# User's articles are published and comments exist
expect(target_articles.map(&:published?)).to match_array([true, true, true])
expect(target_comments.map(&:deleted)).to match_array([false, false, false])
expect(target_articles.map(&:published?)).to contain_exactly(true, true, true)
expect(target_comments.map(&:deleted)).to contain_exactly(false, false, false)
sidekiq_perform_enqueued_jobs(only: Moderator::UnpublishAllArticlesWorker) do
put api_user_unpublish_path(id: target_user.id), headers: auth_headers
@ -238,8 +173,8 @@ RSpec.describe "Api::V1::Users" do
# Ensure article's aren't published and comments deleted
# (with boolean attribute so they can be reverted if needed)
expect(target_articles.map(&:reload).map(&:published?)).to match_array([false, false, false])
expect(target_comments.map(&:reload).map(&:deleted)).to match_array([true, true, true])
expect(target_articles.map(&:reload).map(&:published?)).to contain_exactly(false, false, false)
expect(target_comments.map(&:reload).map(&:deleted)).to contain_exactly(true, true, true)
end
it "creates an audit log of the action taken" do

View file

@ -4,95 +4,199 @@ RSpec.describe Moderator::ManageActivityAndRoles, type: :service do
let(:user) { create(:user) }
let(:admin) { create(:user, :super_admin) }
it "updates user status" do
user.add_role(:suspended)
user.reload
def manage_roles_for(user, user_status:, note: "Test note", acting_as: admin)
described_class.handle_user_roles(
admin: admin,
admin: acting_as,
user: user,
user_params: { note_for_current_role: "warning user", user_status: "Warned" },
user_params: {
note_for_current_role: note,
user_status: user_status
},
)
expect(user.warned?).to be true
expect(user.suspended?).to be false
end
shared_examples_for "elevated role" do |status|
context "when user is in limited role" do
before { user.add_role(:limited) }
it "adding #{status} also removes the limited role" do
expect(user.roles.pluck(:name)).to include("limited") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("limited") # confirm assumptions
end
end
context "when user is in suspended role" do
before { user.add_role(:suspended) }
it "adding #{status} also removes the suspended role" do
expect(user.roles.pluck(:name)).to include("suspended") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("suspended") # confirm assumptions
end
end
context "when user is in warned role" do
before { user.add_role(:warned) }
it "adding #{status} also removes the warned role" do
expect(user.roles.pluck(:name)).to include("warned") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("warned") # confirm assumptions
end
end
context "when user is in comment_suspended role" do
before { user.add_role(:comment_suspended) }
it "adding #{status} also removes the comment_suspended role" do
expect(user.roles.pluck(:name)).to include("comment_suspended") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("comment_suspended") # confirm assumptions
end
end
end
shared_examples_for "negative role" do |status|
context "when user is in trusted role" do
before { user.add_role(:trusted) }
it "adding #{status} removes the trusted role" do
expect(user.roles.pluck(:name)).to include("trusted") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("trusted") # confirm assumptions
end
end
context "when user is in tag_moderator role" do
before { user.add_role(:tag_moderator) }
it "adding #{status} removes the tag_moderator role" do
expect(user.roles.pluck(:name)).to include("tag_moderator") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).not_to include("tag_moderator") # confirm assumptions
end
end
context "when user is in admin role" do
before { user.add_role(:admin) }
it "adding #{status} ignores the admin role" do
expect(user.roles.pluck(:name)).to include("admin") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).to include("admin") # confirm assumptions
end
end
context "when user is in super_moderator role" do
before { user.add_role(:super_moderator) }
it "adding #{status} ignores the super_moderator role" do
expect(user.roles.pluck(:name)).to include("super_moderator") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).to include("super_moderator") # confirm assumptions
end
end
context "when user is in tech_admin role" do
before { user.add_role(:tech_admin) }
it "adding #{status} ignores the tech_admin role" do
expect(user.roles.pluck(:name)).to include("tech_admin") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).to include("tech_admin") # confirm assumptions
end
end
context "when user is in limited role" do
before { user.add_role(:limited) }
it "adding #{status} ignores the limited role" do
expect(user.roles.pluck(:name)).to include("limited") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).to include("limited") # confirm assumptions
end
end
context "when user is in warned role" do
before { user.add_role(:warned) }
it "adding #{status} ignores the warned role" do
expect(user.roles.pluck(:name)).to include("warned") # confirm assumptions
manage_roles_for user, user_status: status
expect(user.roles.pluck(:name)).to include("warned") # confirm assumptions
end
end
end
it_behaves_like "elevated role", "Admin"
it_behaves_like "elevated role", "Super Moderator"
it_behaves_like "elevated role", "Resource Admin: Tag"
it_behaves_like "elevated role", "Super Admin"
it_behaves_like "elevated role", "Trusted"
it_behaves_like "elevated role", "Good standing"
it_behaves_like "elevated role", "Tech Admin"
it_behaves_like "negative role", "Suspended"
it_behaves_like "negative role", "Limited"
it_behaves_like "negative role", "Warned"
context "when user is in suspended role" do
before { user.add_role(:suspended) }
it "adding warned removes the suspended role" do
expect(user.roles.pluck(:name)).to include("suspended") # confirm assumptions
manage_roles_for user, user_status: "Warned"
expect(user.roles.pluck(:name)).not_to include("suspended") # confirm assumptions
end
end
it "updates user status to limited" do
user.add_role(:limited)
user.reload
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "limited user", user_status: "Limited" },
)
expect(user.limited?).to be true
expect(user).not_to be_limited
manage_roles_for(user, user_status: "Limited")
expect(user).to be_limited
manage_roles_for(user, user_status: "Good standing")
expect(user).not_to be_limited
end
it "updates user to super admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Super Admin" },
)
expect(user.super_admin?).to be true
end
it "assigns trusted role to user that's updated to super admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Super Admin" },
)
expect(user.super_admin?).to be true
expect(user).not_to be_super_admin
expect(user.has_trusted_role?).to be false
manage_roles_for(user, user_status: "Super Admin")
expect(user).to be_super_admin
expect(user.has_trusted_role?).to be true
end
it "updates user to admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to admin", user_status: "Admin" },
)
expect(user.admin?).to be true
end
it "assigns trusted role to user that's updated to admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to admin", user_status: "Admin" },
)
expect(user.admin?).to be true
expect(user).not_to be_admin
expect(user.has_trusted_role?).to be false
manage_roles_for(user, user_status: "Admin")
expect(user).to be_admin
expect(user.has_trusted_role?).to be true
end
it "updates user to tech admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to tech admin", user_status: "Tech Admin" },
)
expect(user.tech_admin?).to be true
expect(user).not_to be_tech_admin
expect(user.single_resource_admin_for?(DataUpdateScript)).to be false
manage_roles_for(user, user_status: "Tech Admin")
expect(user).to be_tech_admin
expect(user.single_resource_admin_for?(DataUpdateScript)).to be true
end
it "updates user to single resource admin" do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Resource Admin: Article" },
)
expect(user.single_resource_admin_for?(Article)).to be false
manage_roles_for(user, user_status: "Resource Admin: Article")
expect(user.single_resource_admin_for?(Article)).to be true
end
it "updates negative role to positive role" do
it "user in 'Good standing' has no negative or elevated roles" do
user.add_role(:comment_suspended)
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "user in good standing", user_status: "Good standing" },
)
user.add_role(:warned)
user.add_role(:trusted)
manage_roles_for(user, user_status: "Good standing")
expect(user.suspended?).to be false
expect(user.roles.count).to eq(0)
expect(user.has_trusted_role?).to be false
end
describe "Rack::Attack cache invalidation optimization" do
@ -135,43 +239,27 @@ RSpec.describe Moderator::ManageActivityAndRoles, type: :service do
admin.add_role(:admin)
end
it "updates user to super admin" do
it "raises exception when trying to upgrade user to super admin" do
expect do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Super Admin" },
)
manage_roles_for(user, user_status: "Super Admin")
end.to raise_error(StandardError)
end
it "updates user to admin" do
it "raises exception when trying to upgrade user to admin" do
expect do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Admin" },
)
manage_roles_for(user, user_status: "Admin")
end.to raise_error(StandardError)
end
it "updates user to single resource admin" do
it "raises exception when trying to upgrade user to single resource admin" do
expect do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super admin", user_status: "Resource Admin: Article" },
)
manage_roles_for(user, user_status: "Resource Admin: Article")
end.to raise_error(StandardError)
end
it "updates user to super moderator" do
it "raises exception when trying to upgrade user to super moderator" do
expect do
described_class.handle_user_roles(
admin: admin,
user: user,
user_params: { note_for_current_role: "Upgrading to super_moderator", user_status: "Super Moderator" },
)
manage_roles_for(user, user_status: "Super Moderator")
end.to raise_error(StandardError)
end
end

File diff suppressed because it is too large Load diff