gitlab-org--gitlab-foss/lib/api/users.rb

971 lines
35 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
module API
class Users < ::API::Base
2016-12-04 17:11:19 +00:00
include PaginationParams
include APIGuard
include Helpers::CustomAttributes
allow_access_with_scope :read_user, if: -> (request) { request.get? }
2016-12-04 17:11:19 +00:00
resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do
2017-09-28 16:49:42 +00:00
include CustomAttributesEndpoints
before do
authenticate_non_get!
end
helpers Helpers::UsersHelpers
2016-10-27 08:20:06 +00:00
helpers do
# rubocop: disable CodeReuse/ActiveRecord
def find_user_by_id(params)
id = params[:user_id] || params[:id]
User.find_by(id: id) || not_found!('User')
end
# rubocop: enable CodeReuse/ActiveRecord
# rubocop: disable CodeReuse/ActiveRecord
def reorder_users(users)
if params[:order_by] && params[:sort]
users.reorder(order_options_with_tie_breaker)
else
users
end
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
params :optional_attributes do
optional :skype, type: String, desc: 'The Skype username'
optional :linkedin, type: String, desc: 'The LinkedIn username'
optional :twitter, type: String, desc: 'The Twitter username'
optional :website_url, type: String, desc: 'The website of the user'
optional :organization, type: String, desc: 'The organization of the user'
optional :projects_limit, type: Integer, desc: 'The number of projects a user can create'
2017-01-03 07:44:33 +00:00
optional :extern_uid, type: String, desc: 'The external authentication provider UID'
2016-10-27 08:20:06 +00:00
optional :provider, type: String, desc: 'The external provider'
optional :bio, type: String, desc: 'The biography of the user'
optional :location, type: String, desc: 'The location of the user'
2018-09-26 15:27:26 +00:00
optional :public_email, type: String, desc: 'The public email of the user'
2016-10-27 08:20:06 +00:00
optional :admin, type: Boolean, desc: 'Flag indicating the user is an administrator'
optional :can_create_group, type: Boolean, desc: 'Flag indicating the user can create groups'
optional :external, type: Boolean, desc: 'Flag indicating the user is an external user'
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
optional :avatar, type: File, desc: 'Avatar image for user' # rubocop:disable Scalability/FileUploads
optional :theme_id, type: Integer, desc: 'The GitLab theme for the user'
optional :color_scheme_id, type: Integer, desc: 'The color scheme for the file viewer'
optional :private_profile, type: Boolean, desc: 'Flag indicating the user has a private profile'
optional :note, type: String, desc: 'Admin note for this user'
2016-10-27 08:20:06 +00:00
all_or_none_of :extern_uid, :provider
use :optional_params_ee
2016-10-27 08:20:06 +00:00
end
params :sort_params do
optional :order_by, type: String, values: %w[id name username created_at updated_at],
default: 'id', desc: 'Return users ordered by a field'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return users sorted in ascending and descending order'
end
2016-10-27 08:20:06 +00:00
end
desc 'Get the list of users' do
success Entities::UserBasic
end
params do
2017-04-05 16:31:15 +00:00
# CE
2016-10-27 08:20:06 +00:00
optional :username, type: String, desc: 'Get a single user with a specific username'
optional :extern_uid, type: String, desc: 'Get a single user with a specific external authentication provider UID'
optional :provider, type: String, desc: 'The external provider'
2016-10-27 08:20:06 +00:00
optional :search, type: String, desc: 'Search for a username'
optional :active, type: Boolean, default: false, desc: 'Filters only active users'
optional :external, type: Boolean, default: false, desc: 'Filters only external users'
optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users'
optional :created_after, type: DateTime, desc: 'Return users created after the specified time'
optional :created_before, type: DateTime, desc: 'Return users created before the specified time'
optional :without_projects, type: Boolean, default: false, desc: 'Filters only users without projects'
optional :exclude_internal, as: :non_internal, type: Boolean, default: false, desc: 'Filters only non internal users'
all_or_none_of :extern_uid, :provider
2017-04-05 16:31:15 +00:00
use :sort_params
2016-12-04 17:11:19 +00:00
use :pagination
use :with_custom_attributes
use :optional_index_params_ee
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
2012-06-29 10:46:01 +00:00
get do
authenticated_as_admin! if params[:external].present? || (params[:extern_uid].present? && params[:provider].present?)
2017-07-07 14:09:30 +00:00
unless current_user&.admin?
params.except!(:created_after, :created_before, :order_by, :sort, :two_factor, :without_projects)
end
2017-05-15 13:53:12 +00:00
users = UsersFinder.new(current_user, params).execute
users = reorder_users(users)
authorized = can?(current_user, :read_users_list)
# When `current_user` is not present, require that the `username`
# parameter is passed, to prevent an unauthenticated user from accessing
# a list of all the users on the GitLab instance. `UsersFinder` performs
# an exact match on the `username` parameter, so we are guaranteed to
# get either 0 or 1 `users` here.
authorized &&= params[:username].present? if current_user.blank?
forbidden!("Not authorized to access /api/v4/users") unless authorized
entity = current_user&.admin? ? Entities::UserWithAdmin : Entities::UserBasic
2017-12-04 09:49:53 +00:00
users = users.preload(:identities, :u2f_registrations) if entity == Entities::UserWithAdmin
users = users.preload(:identities, :webauthn_registrations) if entity == Entities::UserWithAdmin
users, options = with_custom_attributes(users, { with: entity, current_user: current_user })
2017-12-04 09:49:53 +00:00
users = users.preload(:user_detail)
present paginate(users), options
2012-06-29 10:46:01 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2012-06-29 10:46:01 +00:00
2016-10-27 08:20:06 +00:00
desc 'Get a single user' do
success Entities::User
2016-10-27 08:20:06 +00:00
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
use :with_custom_attributes
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
2012-06-29 10:46:01 +00:00
get ":id" do
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params[:id])
not_found!('User') unless user && can?(current_user, :read_user, user)
2019-03-22 09:54:03 +00:00
opts = { with: current_user&.admin? ? Entities::UserDetailsWithAdmin : Entities::User, current_user: current_user }
user, opts = with_custom_attributes(user, opts)
present user, opts
2012-06-29 10:46:01 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
desc "Get the status of a user"
params do
2019-01-31 10:13:23 +00:00
requires :user_id, type: String, desc: 'The ID or username of the user'
end
2019-01-31 10:13:23 +00:00
get ":user_id/status", requirements: API::USER_REQUIREMENTS do
user = find_user(params[:user_id])
not_found!('User') unless user && can?(current_user, :read_user, user)
present user.status || {}, with: Entities::UserStatus
end
2016-10-27 08:20:06 +00:00
desc 'Create a user. Available only for admins.' do
success Entities::UserWithAdmin
2016-10-27 08:20:06 +00:00
end
params do
requires :email, type: String, desc: 'The email of the user'
optional :password, type: String, desc: 'The password of the new user'
optional :reset_password, type: Boolean, desc: 'Flag indicating the user will be sent a password reset token'
2017-11-21 15:47:58 +00:00
optional :skip_confirmation, type: Boolean, desc: 'Flag indicating the account is confirmed'
at_least_one_of :password, :reset_password
2016-10-27 08:20:06 +00:00
requires :name, type: String, desc: 'The name of the user'
requires :username, type: String, desc: 'The username of the user'
optional :force_random_password, type: Boolean, desc: 'Flag indicating a random password will be set'
2016-10-27 08:20:06 +00:00
use :optional_attributes
end
post do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
params = declared_params(include_missing: false)
2017-06-19 13:35:44 +00:00
user = ::Users::CreateService.new(current_user, params).execute(skip_authorization: true)
if user.persisted?
present user, with: Entities::UserWithAdmin, current_user: current_user
else
2017-06-21 13:48:12 +00:00
conflict!('Email has already been taken') if User
.by_any_email(user.email.downcase)
.any?
2017-06-21 13:48:12 +00:00
conflict!('Username has already been taken') if User
.by_username(user.username)
.any?
render_validation_error!(user)
end
end
2016-10-27 08:20:06 +00:00
desc 'Update a user. Available only for admins.' do
success Entities::UserWithAdmin
2016-10-27 08:20:06 +00:00
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
optional :email, type: String, desc: 'The email of the user'
optional :password, type: String, desc: 'The password of the new user'
2017-11-21 15:47:58 +00:00
optional :skip_reconfirmation, type: Boolean, desc: 'Flag indicating the account skips the confirmation by email'
2016-10-27 08:20:06 +00:00
optional :name, type: String, desc: 'The name of the user'
optional :username, type: String, desc: 'The username of the user'
use :optional_attributes
end
# rubocop: disable CodeReuse/ActiveRecord
put ":id" do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params.delete(:id))
not_found!('User') unless user
2016-10-27 08:20:06 +00:00
conflict!('Email has already been taken') if params[:email] &&
User.by_any_email(params[:email].downcase)
.where.not(id: user.id).exists?
2016-10-27 08:20:06 +00:00
conflict!('Username has already been taken') if params[:username] &&
User.by_username(params[:username])
.where.not(id: user.id).exists?
user_params = declared_params(include_missing: false)
admin_making_changes_for_another_user = (current_user != user)
if user_params[:password].present?
user_params[:password_expires_at] = Time.current if admin_making_changes_for_another_user
end
result = ::Users::UpdateService.new(current_user, user_params.merge(user: user)).execute do |user|
user.send_only_admin_changed_your_password_notification! if admin_making_changes_for_another_user
end
if result[:status] == :success
present user, with: Entities::UserWithAdmin, current_user: current_user
else
render_validation_error!(user)
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc "Delete a user's identity. Available only for admins" do
success Entities::UserWithAdmin
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :provider, type: String, desc: 'The external provider'
end
# rubocop: disable CodeReuse/ActiveRecord
delete ":id/identities/:provider" do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
identity = user.identities.find_by(provider: params[:provider])
not_found!('Identity') unless identity
destroy_conditionally!(identity)
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Add an SSH key to a specified user. Available only for admins.' do
success Entities::SSHKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key, type: String, desc: 'The new SSH key'
requires :title, type: String, desc: 'The title of the new SSH key'
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
2012-11-14 20:37:52 +00:00
post ":id/keys" do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params.delete(:id))
not_found!('User') unless user
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute
2016-10-27 08:20:06 +00:00
if key.persisted?
2012-11-14 20:37:52 +00:00
present key, with: Entities::SSHKey
else
render_validation_error!(key)
2012-11-14 20:37:52 +00:00
end
end
# rubocop: enable CodeReuse/ActiveRecord
2012-11-14 20:37:52 +00:00
desc 'Get the SSH keys of a specified user.' do
2016-10-27 08:20:06 +00:00
success Entities::SSHKey
end
params do
requires :user_id, type: String, desc: 'The ID or username of the user'
use :pagination
2016-10-27 08:20:06 +00:00
end
get ':user_id/keys', requirements: API::USER_REQUIREMENTS do
user = find_user(params[:user_id])
not_found!('User') unless user && can?(current_user, :read_user, user)
keys = user.keys.preload_users
present paginate(keys), with: Entities::SSHKey
end
2016-10-27 08:20:06 +00:00
desc 'Delete an existing SSH key from a specified user. Available only for admins.' do
success Entities::SSHKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
delete ':id/keys/:key_id' do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params[:id])
not_found!('User') unless user
2016-10-27 08:20:06 +00:00
key = user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
destroy_conditionally!(key) do |key|
destroy_service = ::Keys::DestroyService.new(current_user)
destroy_service.execute(key)
end
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
desc 'Add a GPG key to a specified user. Available only for admins.' do
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
2017-08-25 10:24:41 +00:00
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key, type: String, desc: 'The new GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
post ':id/gpg_keys' do
authenticated_as_admin!
user = User.find_by(id: params.delete(:id))
not_found!('User') unless user
key = ::GpgKeys::CreateService.new(user, declared_params(include_missing: false)).execute
2017-08-25 10:24:41 +00:00
if key.persisted?
present key, with: Entities::GpgKey
2017-08-25 10:24:41 +00:00
else
render_validation_error!(key)
end
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
desc 'Get the GPG keys of a specified user.' do
2017-08-25 10:24:41 +00:00
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
2017-08-25 10:24:41 +00:00
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
get ':id/gpg_keys' do
user = User.find_by(id: params[:id])
not_found!('User') unless user
present paginate(user.gpg_keys), with: Entities::GpgKey
2017-08-25 10:24:41 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
desc 'Get a specific GPG key for a given user.' do
detail 'This feature was added in GitLab 13.5'
success Entities::GpgKey
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
get ':id/gpg_keys/:key_id' do
user = User.find_by(id: params[:id])
not_found!('User') unless user
key = user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
present key, with: Entities::GpgKey
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
desc 'Delete an existing GPG key from a specified user. Available only for admins.' do
detail 'This feature was added in GitLab 10.0'
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
delete ':id/gpg_keys/:key_id' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
key = user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
destroy_conditionally!(key) do |key|
destroy_service = ::GpgKeys::DestroyService.new(current_user)
destroy_service.execute(key)
end
2017-08-25 10:24:41 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
desc 'Revokes an existing GPG key from a specified user. Available only for admins.' do
detail 'This feature was added in GitLab 10.0'
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
post ':id/gpg_keys/:key_id/revoke' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
key = user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
key.revoke
status :accepted
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
2016-10-27 08:20:06 +00:00
desc 'Add an email address to a specified user. Available only for admins.' do
success Entities::Email
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :email, type: String, desc: 'The email of the user'
optional :skip_confirmation, type: Boolean, desc: 'Skip confirmation of email and assume it is verified'
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
post ":id/emails" do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params.delete(:id))
not_found!('User') unless user
2017-09-27 14:39:10 +00:00
email = Emails::CreateService.new(current_user, declared_params(include_missing: false).merge(user: user)).execute
2017-06-22 13:55:05 +00:00
if email.errors.blank?
present email, with: Entities::Email
else
render_validation_error!(email)
end
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Get the emails addresses of a specified user. Available only for admins.' do
success Entities::Email
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
use :pagination
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
get ':id/emails' do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params[:id])
not_found!('User') unless user
present paginate(user.emails), with: Entities::Email
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Delete an email address of a specified user. Available only for admins.' do
success Entities::Email
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
requires :email_id, type: Integer, desc: 'The ID of the email'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
delete ':id/emails/:email_id' do
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User.find_by(id: params[:id])
not_found!('User') unless user
2016-10-27 08:20:06 +00:00
email = user.emails.find_by(id: params[:email_id])
not_found!('Email') unless email
2017-03-02 12:14:13 +00:00
destroy_conditionally!(email) do |email|
Emails::DestroyService.new(current_user, user: user).execute(email)
2017-03-02 12:14:13 +00:00
end
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Delete a user. Available only for admins.' do
success Entities::Email
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
optional :hard_delete, type: Boolean, desc: "Whether to remove a user's contributions"
2016-10-27 08:20:06 +00:00
end
# rubocop: disable CodeReuse/ActiveRecord
delete ":id" do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/issues/20757')
authenticated_as_admin!
2014-01-19 18:55:59 +00:00
user = User.find_by(id: params[:id])
2016-10-27 08:20:06 +00:00
not_found!('User') unless user
conflict!('User cannot be removed while is the sole-owner of a group') unless user.can_be_removed? || params[:hard_delete]
2017-03-02 12:14:13 +00:00
destroy_conditionally!(user) do
user.delete_async(deleted_by: current_user, params: params)
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Activate a deactivated user. Available only for admins.'
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/activate' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
forbidden!('A blocked user must be unblocked to be activated') if user.blocked?
user.activate
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Deactivate an active user. Available only for admins.'
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
post ':id/deactivate' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
not_found!('User') unless user
break if user.deactivated?
unless user.can_be_deactivated?
forbidden!('A blocked user cannot be deactivated by the API') if user.blocked?
forbidden!('An internal user cannot be deactivated by the API') if user.internal?
forbidden!("The user you are trying to deactivate has been active in the past #{::User::MINIMUM_INACTIVE_DAYS} days and cannot be deactivated")
end
if user.deactivate
true
else
render_api_error!(user.errors.full_messages, 400)
end
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Block a user. Available only for admins.'
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-02-20 12:31:11 +00:00
post ':id/block' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
2016-10-27 08:20:06 +00:00
not_found!('User') unless user
if user.ldap_blocked?
forbidden!('LDAP blocked users cannot be modified by the API')
end
break if user.blocked?
result = ::Users::BlockService.new(current_user).execute(user)
if result[:status] == :success
true
else
render_api_error!(result[:message], result[:http_status])
end
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Unblock a user. Available only for admins.'
params do
requires :id, type: Integer, desc: 'The ID of the user'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-02-20 12:31:11 +00:00
post ':id/unblock' do
authenticated_as_admin!
user = User.find_by(id: params[:id])
2016-10-27 08:20:06 +00:00
not_found!('User') unless user
2016-10-27 08:20:06 +00:00
if user.ldap_blocked?
forbidden!('LDAP blocked users cannot be unblocked by the API')
elsif user.deactivated?
forbidden!('Deactivated users cannot be unblocked by the API')
2016-01-12 14:29:10 +00:00
else
user.activate
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get memberships' do
success Entities::Membership
end
params do
requires :user_id, type: Integer, desc: 'The ID of the user'
optional :type, type: String, values: %w[Project Namespace]
use :pagination
end
get ":user_id/memberships" do
authenticated_as_admin!
user = find_user_by_id(params)
members = case params[:type]
when 'Project'
user.project_members
when 'Namespace'
user.group_members
else
user.members
end
members = members.including_source
present paginate(members), with: Entities::Membership
end
params do
requires :user_id, type: Integer, desc: 'The ID of the user'
end
segment ':user_id' do
resource :impersonation_tokens do
helpers do
def finder(options = {})
user = find_user_by_id(params)
PersonalAccessTokensFinder.new({ user: user, impersonation: true }.merge(options))
end
def find_impersonation_token
finder.find_by_id(declared_params[:impersonation_token_id]) || not_found!('Impersonation Token')
end
2017-02-27 18:56:54 +00:00
end
before { authenticated_as_admin! }
desc 'Retrieve impersonation tokens. Available only for admins.' do
detail 'This feature was introduced in GitLab 9.0'
success Entities::ImpersonationToken
end
params do
2017-02-27 18:56:54 +00:00
use :pagination
optional :state, type: String, default: 'all', values: %w[all active inactive], desc: 'Filters (all|active|inactive) impersonation_tokens'
end
get { present paginate(finder(declared_params(include_missing: false)).execute), with: Entities::ImpersonationToken }
desc 'Create a impersonation token. Available only for admins.' do
detail 'This feature was introduced in GitLab 9.0'
success Entities::ImpersonationTokenWithToken
end
params do
requires :name, type: String, desc: 'The name of the impersonation token'
optional :expires_at, type: Date, desc: 'The expiration date in the format YEAR-MONTH-DAY of the impersonation token'
optional :scopes, type: Array, desc: 'The array of scopes of the impersonation token'
end
post do
impersonation_token = finder.build(declared_params(include_missing: false))
if impersonation_token.save
present impersonation_token, with: Entities::ImpersonationTokenWithToken
else
render_validation_error!(impersonation_token)
end
end
desc 'Retrieve impersonation token. Available only for admins.' do
detail 'This feature was introduced in GitLab 9.0'
success Entities::ImpersonationToken
end
params do
requires :impersonation_token_id, type: Integer, desc: 'The ID of the impersonation token'
end
get ':impersonation_token_id' do
present find_impersonation_token, with: Entities::ImpersonationToken
end
desc 'Revoke a impersonation token. Available only for admins.' do
detail 'This feature was introduced in GitLab 9.0'
end
params do
requires :impersonation_token_id, type: Integer, desc: 'The ID of the impersonation token'
end
delete ':impersonation_token_id' do
2017-08-24 08:41:54 +00:00
token = find_impersonation_token
destroy_conditionally!(token) do
token.revoke!
end
end
end
end
2012-06-29 10:46:01 +00:00
end
2012-09-21 11:49:28 +00:00
resource :user do
before do
authenticate!
end
2018-06-13 08:25:01 +00:00
# Enabling /user endpoint for the v3 version to allow oauth
# authentication through this endpoint.
version %w(v3 v4), using: :path do
desc 'Get the currently authenticated user' do
success Entities::UserPublic
end
get do
entity =
if current_user.admin?
Entities::UserWithAdmin
else
Entities::UserPublic
end
present current_user, with: entity, current_user: current_user
2018-06-13 08:25:01 +00:00
end
2012-09-21 11:49:28 +00:00
end
2016-10-27 08:20:06 +00:00
desc "Get the currently authenticated user's SSH keys" do
success Entities::SSHKey
end
params do
use :pagination
end
2012-09-21 11:49:28 +00:00
get "keys" do
keys = current_user.keys.preload_users
present paginate(keys), with: Entities::SSHKey
2012-09-21 11:49:28 +00:00
end
2016-10-27 08:20:06 +00:00
desc 'Get a single key owned by currently authenticated user' do
success Entities::SSHKey
end
params do
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
get "keys/:key_id" do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
2012-09-21 11:49:28 +00:00
present key, with: Entities::SSHKey
end
# rubocop: enable CodeReuse/ActiveRecord
2012-09-21 11:49:28 +00:00
2016-10-27 08:20:06 +00:00
desc 'Add a new SSH key to the currently authenticated user' do
success Entities::SSHKey
end
params do
requires :key, type: String, desc: 'The new SSH key'
requires :title, type: String, desc: 'The title of the new SSH key'
optional :expires_at, type: DateTime, desc: 'The expiration date of the SSH key in ISO 8601 format (YYYY-MM-DDTHH:MM:SSZ)'
2016-10-27 08:20:06 +00:00
end
2012-09-21 11:49:28 +00:00
post "keys" do
key = ::Keys::CreateService.new(current_user, declared_params(include_missing: false)).execute
if key.persisted?
2012-09-21 11:49:28 +00:00
present key, with: Entities::SSHKey
else
render_validation_error!(key)
2012-09-21 11:49:28 +00:00
end
end
2016-10-27 08:20:06 +00:00
desc 'Delete an SSH key from the currently authenticated user' do
success Entities::SSHKey
end
params do
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
delete "keys/:key_id" do
key = current_user.keys.find_by(id: params[:key_id])
not_found!('Key') unless key
destroy_conditionally!(key) do |key|
destroy_service = ::Keys::DestroyService.new(current_user)
destroy_service.execute(key)
end
2012-09-21 11:49:28 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
desc "Get the currently authenticated user's GPG keys" do
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
2017-08-25 10:01:34 +00:00
end
params do
use :pagination
end
get 'gpg_keys' do
present paginate(current_user.gpg_keys), with: Entities::GpgKey
2017-08-25 10:01:34 +00:00
end
desc 'Get a single GPG key owned by currently authenticated user' do
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
2017-08-25 10:01:34 +00:00
end
params do
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
get 'gpg_keys/:key_id' do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
present key, with: Entities::GpgKey
2017-08-25 10:01:34 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
desc 'Add a new GPG key to the currently authenticated user' do
detail 'This feature was added in GitLab 10.0'
success Entities::GpgKey
2017-08-25 10:01:34 +00:00
end
params do
requires :key, type: String, desc: 'The new GPG key'
end
post 'gpg_keys' do
key = ::GpgKeys::CreateService.new(current_user, declared_params(include_missing: false)).execute
2017-08-25 10:01:34 +00:00
if key.persisted?
present key, with: Entities::GpgKey
2017-08-25 10:01:34 +00:00
else
render_validation_error!(key)
end
end
desc 'Revoke a GPG key owned by currently authenticated user' do
detail 'This feature was added in GitLab 10.0'
end
params do
requires :key_id, type: Integer, desc: 'The ID of the GPG key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
post 'gpg_keys/:key_id/revoke' do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
key.revoke
status :accepted
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
desc 'Delete a GPG key from the currently authenticated user' do
detail 'This feature was added in GitLab 10.0'
end
params do
requires :key_id, type: Integer, desc: 'The ID of the SSH key'
end
# rubocop: disable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
delete 'gpg_keys/:key_id' do
key = current_user.gpg_keys.find_by(id: params[:key_id])
not_found!('GPG Key') unless key
destroy_conditionally!(key) do |key|
destroy_service = ::GpgKeys::DestroyService.new(current_user)
destroy_service.execute(key)
end
2017-08-25 10:01:34 +00:00
end
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:01:34 +00:00
2016-10-27 08:20:06 +00:00
desc "Get the currently authenticated user's email addresses" do
success Entities::Email
end
params do
use :pagination
end
get "emails" do
present paginate(current_user.emails), with: Entities::Email
end
2016-10-27 08:20:06 +00:00
desc 'Get a single email address owned by the currently authenticated user' do
success Entities::Email
end
params do
requires :email_id, type: Integer, desc: 'The ID of the email'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
get "emails/:email_id" do
email = current_user.emails.find_by(id: params[:email_id])
not_found!('Email') unless email
present email, with: Entities::Email
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
desc 'Add new email address to the currently authenticated user' do
success Entities::Email
end
params do
requires :email, type: String, desc: 'The new email'
end
post "emails" do
2017-09-27 14:39:10 +00:00
email = Emails::CreateService.new(current_user, declared_params.merge(user: current_user)).execute
2017-06-22 13:55:05 +00:00
if email.errors.blank?
present email, with: Entities::Email
else
render_validation_error!(email)
end
end
2016-10-27 08:20:06 +00:00
desc 'Delete an email address from the currently authenticated user'
params do
requires :email_id, type: Integer, desc: 'The ID of the email'
end
# rubocop: disable CodeReuse/ActiveRecord
2016-10-27 08:20:06 +00:00
delete "emails/:email_id" do
email = current_user.emails.find_by(id: params[:email_id])
not_found!('Email') unless email
2017-03-02 12:14:13 +00:00
destroy_conditionally!(email) do |email|
Emails::DestroyService.new(current_user, user: current_user).execute(email)
2017-03-02 12:14:13 +00:00
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Get a list of user activities'
params do
optional :from, type: DateTime, default: 6.months.ago, desc: 'Date string in the format YEAR-MONTH-DAY'
use :pagination
end
# rubocop: disable CodeReuse/ActiveRecord
get "activities" do
authenticated_as_admin!
2017-06-21 13:48:12 +00:00
activities = User
.where(User.arel_table[:last_activity_on].gteq(params[:from]))
.reorder(last_activity_on: :asc)
present paginate(activities), with: Entities::UserActivity
end
# rubocop: enable CodeReuse/ActiveRecord
desc 'Set the status of the current user' do
success Entities::UserStatus
end
params do
optional :emoji, type: String, desc: "The emoji to set on the status"
optional :message, type: String, desc: "The status message to set"
end
put "status" do
forbidden! unless can?(current_user, :update_user_status, current_user)
if ::Users::SetStatusService.new(current_user, declared_params).execute
present current_user.status, with: Entities::UserStatus
else
render_validation_error!(current_user.status)
end
end
desc 'get the status of the current user' do
success Entities::UserStatus
end
get 'status' do
present current_user.status || {}, with: Entities::UserStatus
end
2012-06-29 10:46:01 +00:00
end
end
end