Add trusted role via API (#20455)
* rubocop * use has_trusted_role? in tests, not trusted? due to pesky caching issues * swagger
This commit is contained in:
parent
199a88a254
commit
78b42c5efd
5 changed files with 2091 additions and 385 deletions
|
|
@ -5,7 +5,7 @@ module Api
|
|||
|
||||
# 'suspended' is also known as 'suspend' for historical reasons
|
||||
SUSPEND_MODE = %w[suspend suspended].freeze
|
||||
ROLES = (SUSPEND_MODE + %w[limited spam]).freeze
|
||||
ROLES = (SUSPEND_MODE + %w[limited spam trusted]).freeze
|
||||
|
||||
before_action :check_role
|
||||
before_action :set_target_user
|
||||
|
|
@ -20,16 +20,16 @@ module Api
|
|||
add_role_to_target_user
|
||||
end
|
||||
|
||||
render json: { success: "okay" }, status: :no_content
|
||||
render json: { success: "okay" }, status: :no_content # rubocop:disable Rails/UnusedRenderContent - adding this as it's been part of the API for a while
|
||||
end
|
||||
|
||||
def destroy
|
||||
# This mechanism for removing roles is pretty specific to limited, suspended and spam,
|
||||
# where they revert to "Good standing" — we would need a different approach,
|
||||
# possibly a whole different service object — to remove *any* roles
|
||||
# This mechanism for removing roles is specific to limited, suspended, spam and trusted.
|
||||
# We revert them 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
|
||||
render json: { success: "okay" }, status: :no_content # rubocop:disable Rails/UnusedRenderContent - adding this as it's been part of the API for a while
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -73,11 +73,11 @@ Rails.application.routes.draw do
|
|||
resources :organizations, only: %i[index create update destroy]
|
||||
|
||||
scope("/users/:id") do
|
||||
constraints(role: /suspend|suspended|limited|spam/) do
|
||||
constraints(role: /suspend|suspended|limited|spam|trusted/) do
|
||||
put "/:role", to: "user_roles#update", as: "user_add_role"
|
||||
end
|
||||
|
||||
constraints(role: /limited|spam/) do
|
||||
constraints(role: /limited|spam|trusted/) do
|
||||
delete "/:role", to: "user_roles#destroy", as: "user_remove_role"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -293,6 +293,112 @@ notify them."
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /users/:id/trusted" do
|
||||
before do
|
||||
user.add_role(:admin)
|
||||
end
|
||||
|
||||
path "/api/users/{id}/trusted" do
|
||||
put "Add trusted role for a User" do
|
||||
tags "users"
|
||||
description "This endpoint allows the client to add the trusted role to a user.
|
||||
The user associated with the API key must have an 'admin' or 'moderator' role.
|
||||
The specified user will be assigned the 'trusted' role. Adding the trusted role to a user
|
||||
allows them to upvote and downvote posts and flag content that needs investigating by admins.
|
||||
Users are notified of this change in the UI, and by email."
|
||||
operationId "trustUser"
|
||||
produces "application/json"
|
||||
parameter name: :id, in: :path, required: true,
|
||||
description: "The ID of the user to assign the trusted role.",
|
||||
schema: {
|
||||
type: :integer,
|
||||
format: :int32,
|
||||
minimum: 1
|
||||
},
|
||||
example: 1
|
||||
|
||||
response "204", "Trusted role assigned to the user successfully" do
|
||||
let(:"api-key") { api_secret.secret }
|
||||
let(:id) { 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) { 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/trusted" do
|
||||
before do
|
||||
user.add_role(:admin)
|
||||
end
|
||||
|
||||
path "/api/users/{id}/trusted" do
|
||||
delete "Remove trusted role from a User" do
|
||||
tags "users"
|
||||
description "This endpoint allows the client to remove the trusted role for a user.
|
||||
The user associated with the API key must have an 'admin' or 'moderator' role.
|
||||
The specified user will be restored to 'general' status. Users are not notified
|
||||
of removing their trusted role in the UI, so if you want them to know about this, you must
|
||||
notify them."
|
||||
operationId "unTrustUser"
|
||||
produces "application/json"
|
||||
parameter name: :id, in: :path, required: true,
|
||||
description: "The ID of the user to remove the trusted role from.",
|
||||
schema: {
|
||||
type: :integer,
|
||||
format: :int32,
|
||||
minimum: 1
|
||||
},
|
||||
example: 1
|
||||
|
||||
response "204", "Successfully removed the trusted role from a user" do
|
||||
let(:"api-key") { api_secret.secret }
|
||||
let(:id) { 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) { 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
|
||||
end
|
||||
# rubocop:enable RSpec/VariableName
|
||||
|
|
|
|||
|
|
@ -287,4 +287,110 @@ RSpec.describe "Api::V1::UserRoles" do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "PUT /api/users/:id/trusted", :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, "trusted"), 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, "trusted"),
|
||||
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(target_user, "trusted"), 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 assigning the trusted role to a user", :aggregate_failures do
|
||||
expect do
|
||||
put api_user_add_role_path(target_user, "trusted"), headers: auth_headers
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(target_user.reload.has_trusted_role?).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, "trusted"), 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_trusted")
|
||||
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/trusted", :aggregate_failures do
|
||||
let(:target_user) { create(:user, :trusted) }
|
||||
|
||||
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, "trusted"), 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, "trusted"),
|
||||
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
|
||||
delete api_user_remove_role_path(target_user, "trusted"), 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 removing the trusted role from a user", :aggregate_failures do
|
||||
expect do
|
||||
delete api_user_remove_role_path(target_user, "trusted"), headers: auth_headers
|
||||
|
||||
expect(response).to have_http_status(:no_content)
|
||||
expect(target_user.reload.has_trusted_role?).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, "trusted"), 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_trusted")
|
||||
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
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue