Commit dd13cc03 authored by Nick Thomas's avatar Nick Thomas

Merge branch '263107-user-admin-approval-approve-user-via-api' into 'master'

Add API post /users/approve for Admin

See merge request gitlab-org/gitlab!47564
parents 6fcec4f2 47faef78
......@@ -7,8 +7,9 @@ module Users
end
def execute(user)
return error(_('You are not allowed to approve a user')) unless allowed?
return error(_('The user you are trying to approve is not pending an approval')) unless approval_required?(user)
return error(_('You are not allowed to approve a user'), :forbidden) unless allowed?
return error(_('The user you are trying to approve is not pending an approval'), :conflict) if user.active?
return error(_('The user you are trying to approve is not pending an approval'), :conflict) unless approval_required?(user)
if user.activate
# Resends confirmation email if the user isn't confirmed yet.
......@@ -18,9 +19,9 @@ module Users
DeviseMailer.user_admin_approval(user).deliver_later
after_approve_hook(user)
success
success(message: 'Success', http_status: :created)
else
error(user.errors.full_messages.uniq.join('. '))
error(user.errors.full_messages.uniq.join('. '), :unprocessable_entity)
end
end
......
---
title: Add API endoint for Administrators to approve pending users
merge_request: 47564
author:
type: added
......@@ -1275,8 +1275,8 @@ Parameters:
Returns:
- `201 OK` on success.
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` when trying to activate a user blocked by admin or by LDAP synchronization.
- `404 User Not Found` if the user cannot be found.
- `403 Forbidden` if the user cannot be activated because they are blocked by an administrator or by LDAP synchronization.
### Get user contribution events
......@@ -1337,6 +1337,44 @@ Example response:
]
```
## Approve user
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/263107) in GitLab 13.7.
Approves the specified user. Available only for administrators.
```plaintext
POST /users/:id/approve
```
Parameters:
- `id` (required) - ID of specified user
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/users/42/approve"
```
Returns:
- `201 OK` on success.
- `404 User Not Found` if user cannot be found.
- `403 Forbidden` if the user cannot be approved because they are blocked by an administrator or by LDAP synchronization.
Example Responses:
```json
{ "message": "Success" }
```
```json
{ "message": "404 User Not Found" }
```
```json
{ "message": "The user you are trying to approve is not pending an approval" }
```
## Get an impersonation token of a user
> Requires admin permissions.
......
......@@ -534,6 +534,24 @@ module API
user.activate
end
desc 'Approve a pending user. Available only for admins.'
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
post ':id/approve', feature_category: :authentication_and_authorization do
user = User.find_by(id: params[:id])
not_found!('User') unless can?(current_user, :read_user, user)
result = ::Users::ApproveService.new(current_user).execute(user)
if result[:success]
result
else
render_api_error!(result[:message], result[:http_status])
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Deactivate an active user. Available only for admins.'
params do
......
......@@ -35,6 +35,10 @@ FactoryBot.define do
user_type { :alert_bot }
end
trait :deactivated do
after(:build) { |user, _| user.deactivate! }
end
trait :project_bot do
user_type { :project_bot }
end
......
......@@ -2510,6 +2510,98 @@ RSpec.describe API::Users, :do_not_mock_admin_mode do
end
end
context 'approve pending user' do
shared_examples '404' do
it 'returns 404' do
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 User Not Found')
end
end
describe 'POST /users/:id/approve' do
subject(:approve) { post api("/users/#{user_id}/approve", api_user) }
let_it_be(:pending_user) { create(:user, :blocked_pending_approval) }
let_it_be(:deactivated_user) { create(:user, :deactivated) }
let_it_be(:blocked_user) { create(:user, :blocked) }
context 'performed by a non-admin user' do
let(:api_user) { user }
let(:user_id) { pending_user.id }
it 'is not authorized to perform the action' do
expect { approve }.not_to change { pending_user.reload.state }
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('You are not allowed to approve a user')
end
end
context 'performed by an admin user' do
let(:api_user) { admin }
context 'for a deactivated user' do
let(:user_id) { deactivated_user.id }
it 'does not approve a deactivated user' do
expect { approve }.not_to change { deactivated_user.reload.state }
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('The user you are trying to approve is not pending an approval')
end
end
context 'for an pending approval user' do
let(:user_id) { pending_user.id }
it 'returns 201' do
expect { approve }.to change { pending_user.reload.state }.to('active')
expect(response).to have_gitlab_http_status(:created)
expect(json_response['message']).to eq('Success')
end
end
context 'for an active user' do
let(:user_id) { user.id }
it 'returns 201' do
expect { approve }.not_to change { user.reload.state }
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('The user you are trying to approve is not pending an approval')
end
end
context 'for a blocked user' do
let(:user_id) { blocked_user.id }
it 'returns 403' do
expect { approve }.not_to change { blocked_user.reload.state }
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('The user you are trying to approve is not pending an approval')
end
end
context 'for a ldap blocked user' do
let(:user_id) { ldap_blocked_user.id }
it 'returns 403' do
expect { approve }.not_to change { ldap_blocked_user.reload.state }
expect(response).to have_gitlab_http_status(:conflict)
expect(json_response['message']).to eq('The user you are trying to approve is not pending an approval')
end
end
context 'for a user that does not exist' do
let(:user_id) { non_existing_record_id }
before do
approve
end
it_behaves_like '404'
end
end
end
end
describe 'POST /users/:id/block' do
let(:blocked_user) { create(:user, state: 'blocked') }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment