2018-09-29 22:34:47 +00:00
# frozen_string_literal: true
2013-05-14 12:33:31 +00:00
module API
2020-10-15 00:08:42 +00:00
class Users < :: API :: Base
2016-12-04 17:11:19 +00:00
include PaginationParams
2017-06-20 07:40:24 +00:00
include APIGuard
2017-12-22 15:54:55 +00:00
include Helpers :: CustomAttributes
2017-06-20 07:40:24 +00:00
2021-02-02 18:09:42 +00:00
allow_access_with_scope :read_user , if : - > ( request ) { request . get? || request . head? }
2016-12-04 17:11:19 +00:00
2022-10-26 12:11:43 +00:00
feature_category :users ,
%w[
/ users / :id / custom_attributes
/ users / :id / custom_attributes / :key
/ users / :id / associations_count
]
2020-10-26 18:08:27 +00:00
2022-10-26 12:11:43 +00:00
urgency :medium ,
%w[
/ users / :id / custom_attributes
/ users / :id / custom_attributes / :key
]
2022-04-21 15:10:09 +00:00
2015-08-13 13:35:42 +00:00
resource :users , requirements : { uid : / [0-9]* / , id : / [0-9]* / } do
2017-09-28 16:49:42 +00:00
include CustomAttributesEndpoints
2017-07-04 12:19:48 +00:00
before do
authenticate_non_get!
end
2019-05-28 10:14:26 +00:00
helpers Helpers :: UsersHelpers
2022-10-27 09:10:57 +00:00
helpers Gitlab :: Tracking :: Helpers :: WeakPasswordErrorEvent
2019-05-28 10:14:26 +00:00
2016-10-27 08:20:06 +00:00
helpers do
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2018-02-06 13:37:52 +00:00
def reorder_users ( users )
if params [ :order_by ] && params [ :sort ]
2019-02-16 10:03:42 +00:00
users . reorder ( order_options_with_tie_breaker )
2018-02-06 13:37:52 +00:00
else
users
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2018-02-06 13:37:52 +00:00
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'
2022-09-28 18:08:30 +00:00
optional :pronouns , type : String , desc : 'The pronouns of the user'
2018-09-26 15:27:26 +00:00
optional :public_email , type : String , desc : 'The public email of the user'
2022-09-27 12:10:16 +00:00
optional :commit_email , type : String , desc : 'The commit email, _private for private commit email'
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'
2022-10-18 09:11:01 +00:00
optional :avatar , type : :: API :: Validations :: Types :: WorkhorseFile , desc : 'Avatar image for user' , documentation : { type : 'file' }
2020-03-14 00:09:30 +00:00
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'
2020-02-06 21:08:48 +00:00
optional :private_profile , type : Boolean , desc : 'Flag indicating the user has a private profile'
2020-05-28 09:08:05 +00:00
optional :note , type : String , desc : 'Admin note for this user'
2021-02-25 06:10:51 +00:00
optional :view_diffs_file_by_file , type : Boolean , desc : 'Flag indicating the user sees only one file diff per page'
2016-10-27 08:20:06 +00:00
all_or_none_of :extern_uid , :provider
2019-03-25 14:33:16 +00:00
2019-05-28 10:14:26 +00:00
use :optional_params_ee
2016-10-27 08:20:06 +00:00
end
2018-02-06 13:37:52 +00:00
params :sort_params do
optional :order_by , type : String , values : %w[ id name username created_at updated_at ] ,
2022-08-12 15:11:42 +00:00
default : 'id' , desc : 'Return users ordered by a field'
2018-02-06 13:37:52 +00:00
optional :sort , type : String , values : %w[ asc desc ] , default : 'desc' ,
2022-08-12 15:11:42 +00:00
desc : 'Return users sorted in ascending and descending order'
2018-02-06 13:37:52 +00:00
end
2016-10-27 08:20:06 +00:00
end
2022-10-26 12:11:43 +00:00
resources ':id/associations_count' do
helpers do
def present_entity ( result )
present result ,
with : :: API :: Entities :: UserAssociationsCount
end
end
desc " Returns a list of a specified user's count of projects, groups, issues and merge requests. "
params do
requires :id ,
type : Integer ,
desc : 'ID of the user to query.'
end
get do
authenticate!
user = find_user_by_id ( params )
forbidden! unless can? ( current_user , :get_user_associations_count , user )
not_found! ( 'User' ) unless user
present_entity ( user )
end
end
2016-10-27 08:20:06 +00:00
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'
2017-02-16 01:44:36 +00:00
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'
2021-02-24 15:11:10 +00:00
optional :exclude_external , as : :non_external , type : Boolean , default : false , desc : 'Filters only non external users'
2016-10-27 08:20:06 +00:00
optional :blocked , type : Boolean , default : false , desc : 'Filters only blocked users'
2017-07-07 07:29:00 +00:00
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'
2020-04-15 09:09:46 +00:00
optional :without_projects , type : Boolean , default : false , desc : 'Filters only users without projects'
2020-08-31 15:10:41 +00:00
optional :exclude_internal , as : :non_internal , type : Boolean , default : false , desc : 'Filters only non internal users'
2022-03-31 00:08:33 +00:00
optional :without_project_bots , type : Boolean , default : false , desc : 'Filters users without project bots'
2021-01-18 12:10:41 +00:00
optional :admins , type : Boolean , default : false , desc : 'Filters only admin users'
2017-02-16 01:44:36 +00:00
all_or_none_of :extern_uid , :provider
2017-04-05 16:31:15 +00:00
2018-02-06 13:37:52 +00:00
use :sort_params
2016-12-04 17:11:19 +00:00
use :pagination
2017-12-22 15:54:55 +00:00
use :with_custom_attributes
2019-05-28 10:14:26 +00:00
use :optional_index_params_ee
2016-10-27 08:20:06 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2022-05-11 12:09:03 +00:00
get feature_category : :users , urgency : :low do
2021-02-24 15:11:10 +00:00
authenticated_as_admin! if params [ :extern_uid ] . present? && params [ :provider ] . present?
2017-02-16 01:44:36 +00:00
2017-07-07 14:09:30 +00:00
unless current_user & . admin?
2020-04-15 09:09:46 +00:00
params . except! ( :created_after , :created_before , :order_by , :sort , :two_factor , :without_projects )
2017-07-07 07:29:00 +00:00
end
2017-06-29 07:43:41 +00:00
authorized = can? ( current_user , :read_users_list )
2017-06-26 07:20:30 +00:00
2017-06-29 07:43:41 +00:00
# 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?
2017-06-26 07:20:30 +00:00
2017-06-29 07:43:41 +00:00
forbidden! ( " Not authorized to access /api/v4/users " ) unless authorized
2022-02-26 00:14:54 +00:00
users = UsersFinder . new ( current_user , params ) . execute
users = reorder_users ( users )
2017-06-29 07:43:41 +00:00
entity = current_user & . admin? ? Entities :: UserWithAdmin : Entities :: UserBasic
2022-03-22 12:07:28 +00:00
if entity == Entities :: UserWithAdmin
2022-07-08 09:09:44 +00:00
users = users . preload ( :identities , :u2f_registrations , :webauthn_registrations , :namespace , :followers , :followees , :user_preference )
2022-03-22 12:07:28 +00:00
end
2018-07-24 12:46:19 +00:00
users , options = with_custom_attributes ( users , { with : entity , current_user : current_user } )
2017-12-04 09:49:53 +00:00
2020-07-10 00:09:13 +00:00
users = users . preload ( :user_detail )
2017-12-22 15:54:55 +00:00
present paginate ( users ) , options
2012-06-29 10:46:01 +00:00
end
2018-08-27 15:31:01 +00:00
# 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
2017-08-11 12:08:20 +00:00
success Entities :: User
2016-10-27 08:20:06 +00:00
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
2017-12-22 15:54:55 +00:00
use :with_custom_attributes
2016-10-27 08:20:06 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2022-06-03 09:08:43 +00:00
get " :id " , feature_category : :users , urgency : :low do
2021-09-30 18:11:31 +00:00
forbidden! ( 'Not authorized!' ) unless current_user
2022-03-04 12:13:07 +00:00
unless current_user . admin?
check_rate_limit! ( :users_get_by_id ,
scope : current_user ,
users_allowlist : Gitlab :: CurrentSettings . current_application_settings . users_get_by_id_limit_allowlist
)
2021-12-20 15:12:25 +00:00
end
2016-10-27 08:20:06 +00:00
user = User . find_by ( id : params [ :id ] )
2021-09-30 18:11:31 +00:00
2017-08-11 12:08:20 +00:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
2021-12-20 15:12:25 +00:00
opts = { with : current_user . admin? ? Entities :: UserDetailsWithAdmin : Entities :: User , current_user : current_user }
2017-12-22 15:54:55 +00:00
user , opts = with_custom_attributes ( user , opts )
2017-08-11 12:08:20 +00:00
present user , opts
2012-06-29 10:46:01 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2012-10-19 10:23:10 +00:00
2018-07-13 15:52:31 +00:00
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'
2018-07-13 15:52:31 +00:00
end
2022-05-20 21:08:53 +00:00
get " :user_id/status " , requirements : API :: USER_REQUIREMENTS , feature_category : :users , urgency : :default do
2019-01-31 10:13:23 +00:00
user = find_user ( params [ :user_id ] )
2021-09-30 18:11:31 +00:00
2018-07-13 15:52:31 +00:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
present user . status || { } , with : Entities :: UserStatus
end
2021-02-15 21:08:59 +00:00
desc 'Follow a user' do
success Entities :: User
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
post ':id/follow' , feature_category : :users do
user = find_user ( params [ :id ] )
not_found! ( 'User' ) unless user
2022-10-13 09:37:59 +00:00
followee = current_user . follow ( user )
if followee & . errors & . any?
render_api_error! ( followee . errors . full_messages . join ( ', ' ) , 400 )
elsif followee & . persisted?
2021-02-15 21:08:59 +00:00
present user , with : Entities :: UserBasic
else
not_modified!
end
end
desc 'Unfollow a user' do
success Entities :: User
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
post ':id/unfollow' , feature_category : :users do
user = find_user ( params [ :id ] )
not_found! ( 'User' ) unless user
if current_user . unfollow ( user )
present user , with : Entities :: UserBasic
else
not_modified!
end
end
desc 'Get the users who follow a user' do
success Entities :: UserBasic
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
use :pagination
end
get ':id/following' , feature_category : :users do
2021-09-30 18:11:31 +00:00
forbidden! ( 'Not authorized!' ) unless current_user
2021-02-15 21:08:59 +00:00
user = find_user ( params [ :id ] )
not_found! ( 'User' ) unless user && can? ( current_user , :read_user_profile , user )
present paginate ( user . followees ) , with : Entities :: UserBasic
end
desc 'Get the followers of a user' do
success Entities :: UserBasic
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
use :pagination
end
get ':id/followers' , feature_category : :users do
2021-09-30 18:11:31 +00:00
forbidden! ( 'Not authorized!' ) unless current_user
2021-02-15 21:08:59 +00:00
user = find_user ( params [ :id ] )
not_found! ( 'User' ) unless user && can? ( current_user , :read_user_profile , user )
present paginate ( user . followers ) , with : Entities :: UserBasic
end
2016-10-27 08:20:06 +00:00
desc 'Create a user. Available only for admins.' do
2019-07-16 09:22:40 +00:00
success Entities :: UserWithAdmin
2016-10-27 08:20:06 +00:00
end
params do
requires :email , type : String , desc : 'The email of the user'
2017-02-03 14:49:27 +00:00
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'
2021-04-01 00:09:32 +00:00
at_least_one_of :password , :reset_password , :force_random_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'
2019-06-27 19:41:51 +00:00
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
2020-10-26 18:08:27 +00:00
post feature_category : :users do
2012-10-02 09:46:01 +00:00
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
2017-03-27 09:37:24 +00:00
params = declared_params ( include_missing : false )
2021-05-31 15:11:12 +00:00
user = :: Users :: AuthorizedCreateService . new ( current_user , params ) . execute
2017-02-03 14:49:27 +00:00
2017-03-27 09:37:24 +00:00
if user . persisted?
2019-07-16 09:22:40 +00:00
present user , with : Entities :: UserWithAdmin , current_user : current_user
2012-10-02 09:46:01 +00:00
else
2017-06-21 13:48:12 +00:00
conflict! ( 'Email has already been taken' ) if User
2018-10-18 09:06:44 +00:00
. by_any_email ( user . email . downcase )
. any?
2014-08-18 18:09:09 +00:00
2017-06-21 13:48:12 +00:00
conflict! ( 'Username has already been taken' ) if User
2018-10-18 09:06:44 +00:00
. by_username ( user . username )
. any?
2014-08-18 18:09:09 +00:00
2022-10-27 09:10:57 +00:00
track_weak_password_error ( user , 'API::Users' , 'create' )
2014-08-18 18:09:09 +00:00
render_validation_error! ( user )
2012-10-02 09:46:01 +00:00
end
end
2012-12-18 19:24:31 +00:00
2016-10-27 08:20:06 +00:00
desc 'Update a user. Available only for admins.' do
2019-07-16 09:22:40 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
put " :id " , feature_category : :users do
2012-12-18 19:24:31 +00:00
authenticated_as_admin!
2013-02-20 11:10:51 +00:00
2016-10-27 08:20:06 +00:00
user = User . find_by ( id : params . delete ( :id ) )
2014-08-18 18:09:09 +00:00
not_found! ( 'User' ) unless user
2012-12-18 19:24:31 +00:00
2016-10-27 08:20:06 +00:00
conflict! ( 'Email has already been taken' ) if params [ :email ] &&
2018-10-18 09:06:44 +00:00
User . by_any_email ( params [ :email ] . downcase )
2020-03-23 09:09:42 +00:00
. where . not ( id : user . id ) . exists?
2014-08-18 18:09:09 +00:00
2016-10-27 08:20:06 +00:00
conflict! ( 'Username has already been taken' ) if params [ :username ] &&
2018-10-18 09:06:44 +00:00
User . by_username ( params [ :username ] )
2020-03-23 09:09:42 +00:00
. where . not ( id : user . id ) . exists?
2014-08-18 18:09:09 +00:00
2016-11-21 16:44:24 +00:00
user_params = declared_params ( include_missing : false )
2020-09-04 09:08:38 +00:00
admin_making_changes_for_another_user = ( current_user != user )
2015-09-22 21:26:59 +00:00
2020-09-04 09:08:38 +00:00
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
2017-06-15 14:42:14 +00:00
if result [ :status ] == :success
2019-07-16 09:22:40 +00:00
present user , with : Entities :: UserWithAdmin , current_user : current_user
2012-12-18 19:24:31 +00:00
else
2022-10-27 09:10:57 +00:00
track_weak_password_error ( user , 'API::Users' , 'update' )
2014-08-18 18:09:09 +00:00
render_validation_error! ( user )
2012-12-18 19:24:31 +00:00
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2012-12-18 19:24:31 +00:00
2022-06-20 09:09:39 +00:00
desc " Disable two factor authentication for a user. Available only for admins " do
detail 'This feature was added in GitLab 15.2'
success Entities :: UserWithAdmin
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
patch " :id/disable_two_factor " , feature_category : :authentication_and_authorization do
authenticated_as_admin!
user = User . find_by_id ( params [ :id ] )
not_found! ( 'User' ) unless user
forbidden! ( 'Two-factor authentication for admins cannot be disabled via the API. Use the Rails console' ) if user . admin?
result = TwoFactor :: DestroyService . new ( current_user , user : user ) . execute
if result [ :status ] == :success
no_content!
else
bad_request! ( result [ :message ] )
end
end
2020-02-14 12:09:03 +00:00
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
2020-10-26 18:08:27 +00:00
delete " :id/identities/:provider " , feature_category : :authentication_and_authorization do
2020-02-14 12:09:03 +00:00
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
2022-06-13 09:09:24 +00:00
desc 'Get the project-level Deploy keys that a specified user can access to.' do
success Entities :: DeployKey
end
params do
requires :user_id , type : String , desc : 'The ID or username of the user'
use :pagination
end
get ':user_id/project_deploy_keys' , requirements : API :: USER_REQUIREMENTS , feature_category : :continuous_delivery do
user = find_user ( params [ :user_id ] )
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
project_ids = Project . visible_to_user_and_access_level ( current_user , Gitlab :: Access :: MAINTAINER )
unless current_user == user
# Restrict to only common projects of both current_user and user.
project_ids = project_ids . visible_to_user_and_access_level ( user , Gitlab :: Access :: MAINTAINER )
end
forbidden! ( 'No common authorized project found' ) unless project_ids . present?
keys = DeployKey . in_projects ( project_ids )
present paginate ( keys ) , with : Entities :: DeployKey
end
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
2022-11-09 12:07:48 +00:00
requires :user_id , type : Integer , desc : 'The ID of the user'
2016-10-27 08:20:06 +00:00
requires :key , type : String , desc : 'The new SSH key'
requires :title , type : String , desc : 'The title of the new SSH key'
2020-06-04 00:08:17 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2022-11-09 12:07:48 +00:00
post " :user_id/keys " , feature_category : :authentication_and_authorization do
2012-11-14 20:37:52 +00:00
authenticated_as_admin!
2014-08-18 18:09:09 +00:00
2022-11-09 12:07:48 +00:00
user = User . find_by ( id : params . delete ( :user_id ) )
2016-10-27 08:20:06 +00:00
not_found! ( 'User' ) unless user
2020-06-15 12:08:44 +00:00
key = :: Keys :: CreateService . new ( current_user , declared_params ( include_missing : false ) . merge ( user : user ) ) . execute
2016-10-27 08:20:06 +00:00
2020-06-15 12:08:44 +00:00
if key . persisted?
2012-11-14 20:37:52 +00:00
present key , with : Entities :: SSHKey
else
2014-08-18 18:09:09 +00:00
render_validation_error! ( key )
2012-11-14 20:37:52 +00:00
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2012-11-14 20:37:52 +00:00
2018-06-28 06:13:21 +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
2020-01-20 09:08:32 +00:00
requires :user_id , type : String , desc : 'The ID or username of the user'
2017-01-17 04:45:07 +00:00
use :pagination
2016-10-27 08:20:06 +00:00
end
2020-10-26 18:08:27 +00:00
get ':user_id/keys' , requirements : API :: USER_REQUIREMENTS , feature_category : :authentication_and_authorization do
2020-01-20 09:08:32 +00:00
user = find_user ( params [ :user_id ] )
2018-06-28 06:13:21 +00:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
2014-08-18 18:09:09 +00:00
2020-06-15 18:08:43 +00:00
keys = user . keys . preload_users
present paginate ( keys ) , with : Entities :: SSHKey
2014-04-15 14:39:46 +00:00
end
2022-03-03 12:14:02 +00:00
desc 'Get a SSH key of a specified user.' 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
get ':id/keys/:key_id' , requirements : API :: USER_REQUIREMENTS , feature_category : :authentication_and_authorization do
user = find_user ( params [ :id ] )
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
key = user . keys . find_by ( id : params [ :key_id ] ) # rubocop: disable CodeReuse/ActiveRecord
not_found! ( 'Key' ) unless key
present key , 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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete ':id/keys/:key_id' , feature_category : :authentication_and_authorization do
2014-04-15 14:39:46 +00:00
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User . find_by ( id : params [ :id ] )
2014-08-18 18:09:09 +00:00
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
2020-06-16 15:08:32 +00:00
destroy_conditionally! ( key ) do | key |
destroy_service = :: Keys :: DestroyService . new ( current_user )
destroy_service . execute ( key )
end
2014-04-15 14:39:46 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2014-04-15 14:39:46 +00:00
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'
2020-03-07 03:08:03 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post ':id/gpg_keys' , feature_category : :authentication_and_authorization do
2017-08-25 10:24:41 +00:00
authenticated_as_admin!
user = User . find_by ( id : params . delete ( :id ) )
not_found! ( 'User' ) unless user
2020-06-19 12:09:07 +00:00
key = :: GpgKeys :: CreateService . new ( user , declared_params ( include_missing : false ) ) . execute
2017-08-25 10:24:41 +00:00
2020-06-19 12:09:07 +00:00
if key . persisted?
2020-03-07 03:08:03 +00:00
present key , with : Entities :: GpgKey
2017-08-25 10:24:41 +00:00
else
render_validation_error! ( key )
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
2020-09-30 00:09:53 +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'
2020-03-07 03:08:03 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get ':id/gpg_keys' , feature_category : :authentication_and_authorization do
2017-08-25 10:24:41 +00:00
user = User . find_by ( id : params [ :id ] )
not_found! ( 'User' ) unless user
2020-03-07 03:08:03 +00:00
present paginate ( user . gpg_keys ) , with : Entities :: GpgKey
2017-08-25 10:24:41 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 10:24:41 +00:00
2020-10-07 18:08:34 +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
2020-10-26 18:08:27 +00:00
get ':id/gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2020-10-07 18:08:34 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete ':id/gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 10:24:41 +00:00
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
2020-06-22 12:08:47 +00:00
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
2018-08-27 15:31:01 +00:00
# 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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post ':id/gpg_keys/:key_id/revoke' , feature_category : :authentication_and_authorization do
2017-08-25 10:24:41 +00:00
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
2018-08-27 15:31:01 +00:00
# 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'
2018-09-09 21:04:11 +00:00
optional :skip_confirmation , type : Boolean , desc : 'Skip confirmation of email and assume it is verified'
2016-10-27 08:20:06 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post " :id/emails " , feature_category : :users do
2015-07-29 13:40:08 +00:00
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?
2015-07-29 13:40:08 +00:00
present email , with : Entities :: Email
else
render_validation_error! ( email )
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 13:40:08 +00:00
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'
2017-01-17 04:45:07 +00:00
use :pagination
2016-10-27 08:20:06 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get ':id/emails' , feature_category : :users do
2015-07-29 13:40:08 +00:00
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User . find_by ( id : params [ :id ] )
2015-07-29 13:40:08 +00:00
not_found! ( 'User' ) unless user
2017-01-17 04:45:07 +00:00
present paginate ( user . emails ) , with : Entities :: Email
2015-07-29 13:40:08 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 13:40:08 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete ':id/emails/:email_id' , feature_category : :users do
2015-07-29 13:40:08 +00:00
authenticated_as_admin!
2016-10-27 08:20:06 +00:00
user = User . find_by ( id : params [ :id ] )
2015-07-29 13:40:08 +00:00
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
2015-07-29 13:40:08 +00:00
2017-03-02 12:14:13 +00:00
destroy_conditionally! ( email ) do | email |
2017-10-05 10:48:22 +00:00
Emails :: DestroyService . new ( current_user , user : user ) . execute ( email )
2017-03-02 12:14:13 +00:00
end
2015-07-29 13:40:08 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 13:40:08 +00:00
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'
2017-06-01 16:14:39 +00:00
optional :hard_delete , type : Boolean , desc : " Whether to remove a user's contributions "
2016-10-27 08:20:06 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete " :id " , feature_category : :users do
2012-12-18 19:24:31 +00:00
authenticated_as_admin!
2017-03-01 13:35:48 +00:00
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
2019-12-12 00:07:43 +00:00
conflict! ( 'User cannot be removed while is the sole-owner of a group' ) unless user . can_be_removed? || params [ :hard_delete ]
2012-12-18 19:24:31 +00:00
2017-03-02 12:14:13 +00:00
destroy_conditionally! ( user ) do
user . delete_async ( deleted_by : current_user , params : params )
end
2012-12-18 19:24:31 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-04-28 16:02:44 +00:00
2019-10-10 00:06:44 +00:00
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
2020-10-26 18:08:27 +00:00
post ':id/activate' , feature_category : :authentication_and_authorization do
2019-10-10 00:06:44 +00:00
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
2020-11-23 12:09:11 +00:00
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
2021-09-09 09:11:16 +00:00
desc 'Reject a pending user. Available only for admins.'
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
post ':id/reject' , feature_category : :authentication_and_authorization do
user = find_user_by_id ( params )
result = :: Users :: RejectService . new ( current_user ) . execute ( user )
if result [ :success ]
present user
else
render_api_error! ( result [ :message ] , result [ :http_status ] )
end
end
2019-10-10 00:06:44 +00:00
# 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
2020-10-26 18:08:27 +00:00
post ':id/deactivate' , feature_category : :authentication_and_authorization do
2019-10-10 00:06:44 +00:00
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?
2020-10-14 06:08:33 +00:00
forbidden! ( 'An internal user cannot be deactivated by the API' ) if user . internal?
2022-08-25 15:12:14 +00:00
forbidden! ( " The user you are trying to deactivate has been active in the past #{ Gitlab :: CurrentSettings . deactivate_dormant_users_period } days and cannot be deactivated " )
2019-10-10 00:06:44 +00:00
end
2020-10-14 06:08:33 +00:00
if user . deactivate
true
else
render_api_error! ( user . errors . full_messages , 400 )
end
2019-10-10 00:06:44 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post ':id/block' , feature_category : :authentication_and_authorization do
2015-04-28 16:02:44 +00:00
authenticated_as_admin!
user = User . find_by ( id : params [ :id ] )
2016-10-27 08:20:06 +00:00
not_found! ( 'User' ) unless user
2015-04-28 16:02:44 +00:00
2020-03-04 12:07:52 +00:00
if user . ldap_blocked?
2015-12-30 18:52:02 +00:00
forbidden! ( 'LDAP blocked users cannot be modified by the API' )
2022-03-09 06:07:38 +00:00
elsif current_user == user
forbidden! ( 'The API initiating user cannot be blocked by the API' )
2015-04-28 16:02:44 +00:00
end
2020-03-04 12:07:52 +00:00
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
2015-04-28 16:02:44 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-04-28 16:02:44 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post ':id/unblock' , feature_category : :authentication_and_authorization do
2015-04-28 16:02:44 +00:00
authenticated_as_admin!
user = User . find_by ( id : params [ :id ] )
2016-10-27 08:20:06 +00:00
not_found! ( 'User' ) unless user
2015-04-28 16:02:44 +00:00
2016-10-27 08:20:06 +00:00
if user . ldap_blocked?
2015-12-30 18:52:02 +00:00
forbidden! ( 'LDAP blocked users cannot be unblocked by the API' )
2019-10-10 00:06:44 +00:00
elsif user . deactivated?
forbidden! ( 'Deactivated users cannot be unblocked by the API' )
2016-01-12 14:29:10 +00:00
else
user . activate
2015-04-28 16:02:44 +00:00
end
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2016-10-10 11:35:26 +00:00
2021-08-26 09:11:15 +00:00
desc 'Ban a user. Available only for admins.'
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
post ':id/ban' , feature_category : :authentication_and_authorization do
authenticated_as_admin!
user = find_user_by_id ( params )
result = :: Users :: BanService . new ( current_user ) . execute ( user )
if result [ :status ] == :success
true
else
render_api_error! ( result [ :message ] , result [ :http_status ] )
end
end
desc 'Unban a user. Available only for admins.'
params do
requires :id , type : Integer , desc : 'The ID of the user'
end
post ':id/unban' , feature_category : :authentication_and_authorization do
authenticated_as_admin!
user = find_user_by_id ( params )
result = :: Users :: UnbanService . new ( current_user ) . execute ( user )
if result [ :status ] == :success
true
else
render_api_error! ( result [ :message ] , result [ :http_status ] )
end
end
2020-01-22 15:08:48 +00:00
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
2022-04-21 15:10:09 +00:00
get " :user_id/memberships " , feature_category : :users , urgency : :high do
2020-01-22 15:08:48 +00:00
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
2016-12-27 16:26:57 +00:00
params do
2017-03-01 16:59:03 +00:00
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 = { } )
2017-09-21 14:10:33 +00:00
user = find_user_by_id ( params )
2017-03-01 16:59:03 +00:00
PersonalAccessTokensFinder . new ( { user : user , impersonation : true } . merge ( options ) )
end
def find_impersonation_token
2018-10-26 14:47:03 +00:00
finder . find_by_id ( declared_params [ :impersonation_token_id ] ) || not_found! ( 'Impersonation Token' )
2017-03-01 16:59:03 +00:00
end
2017-02-27 18:56:54 +00:00
end
2016-12-27 16:26:57 +00:00
2017-03-01 16:59:03 +00:00
before { authenticated_as_admin! }
desc 'Retrieve impersonation tokens. Available only for admins.' do
2017-02-09 15:21:09 +00:00
detail 'This feature was introduced in GitLab 9.0'
2017-02-23 17:47:06 +00:00
success Entities :: ImpersonationToken
2017-02-09 15:21:09 +00:00
end
params do
2017-02-27 18:56:54 +00:00
use :pagination
2017-03-01 16:59:03 +00:00
optional :state , type : String , default : 'all' , values : %w[ all active inactive ] , desc : 'Filters (all|active|inactive) impersonation_tokens'
2017-02-09 15:21:09 +00:00
end
2021-09-28 12:11:10 +00:00
get feature_category : :authentication_and_authorization do
2020-10-26 18:08:27 +00:00
present paginate ( finder ( declared_params ( include_missing : false ) ) . execute ) , with : Entities :: ImpersonationToken
end
2016-12-27 16:26:57 +00:00
2017-03-01 16:59:03 +00:00
desc 'Create a impersonation token. Available only for admins.' do
2017-02-09 15:21:09 +00:00
detail 'This feature was introduced in GitLab 9.0'
2018-11-08 15:03:56 +00:00
success Entities :: ImpersonationTokenWithToken
2017-02-09 15:21:09 +00:00
end
params do
2017-03-01 16:59:03 +00:00
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'
2022-10-18 09:11:01 +00:00
optional :scopes , type : Array [ String ] , coerce_with : :: API :: Validations :: Types :: CommaSeparatedToArray . coerce , desc : 'The array of scopes of the impersonation token'
2017-02-09 15:21:09 +00:00
end
2020-10-26 18:08:27 +00:00
post feature_category : :authentication_and_authorization do
2017-03-01 16:59:03 +00:00
impersonation_token = finder . build ( declared_params ( include_missing : false ) )
2017-02-09 15:21:09 +00:00
2017-03-01 16:59:03 +00:00
if impersonation_token . save
2018-11-08 15:03:56 +00:00
present impersonation_token , with : Entities :: ImpersonationTokenWithToken
2017-02-09 15:21:09 +00:00
else
2017-03-01 16:59:03 +00:00
render_validation_error! ( impersonation_token )
2017-02-09 15:21:09 +00:00
end
end
2016-12-27 16:26:57 +00:00
2017-03-01 16:59:03 +00:00
desc 'Retrieve impersonation token. Available only for admins.' do
2017-02-09 15:21:09 +00:00
detail 'This feature was introduced in GitLab 9.0'
2017-02-23 17:47:06 +00:00
success Entities :: ImpersonationToken
2017-02-09 15:21:09 +00:00
end
params do
2017-03-01 16:59:03 +00:00
requires :impersonation_token_id , type : Integer , desc : 'The ID of the impersonation token'
2017-02-09 15:21:09 +00:00
end
2020-10-26 18:08:27 +00:00
get ':impersonation_token_id' , feature_category : :authentication_and_authorization do
2017-03-01 16:59:03 +00:00
present find_impersonation_token , with : Entities :: ImpersonationToken
2017-02-09 15:21:09 +00:00
end
2016-12-27 16:26:57 +00:00
2017-03-01 16:59:03 +00:00
desc 'Revoke a impersonation token. Available only for admins.' do
2017-02-09 15:21:09 +00:00
detail 'This feature was introduced in GitLab 9.0'
end
params do
2017-03-01 16:59:03 +00:00
requires :impersonation_token_id , type : Integer , desc : 'The ID of the impersonation token'
2017-02-09 15:21:09 +00:00
end
2020-10-26 18:08:27 +00:00
delete ':impersonation_token_id' , feature_category : :authentication_and_authorization do
2017-08-24 08:41:54 +00:00
token = find_impersonation_token
destroy_conditionally! ( token ) do
token . revoke!
end
2017-02-09 15:21:09 +00:00
end
end
2020-11-16 12:09:05 +00:00
resource :personal_access_tokens do
helpers do
def target_user
find_user_by_id ( params )
end
end
before { authenticated_as_admin! }
desc 'Create a personal access token. Available only for admins.' do
detail 'This feature was introduced in GitLab 13.6'
success Entities :: PersonalAccessTokenWithToken
end
params do
requires :name , type : String , desc : 'The name of the personal access token'
requires :scopes , type : Array [ String ] , coerce_with : :: API :: Validations :: Types :: CommaSeparatedToArray . coerce , values : :: Gitlab :: Auth . all_available_scopes . map ( & :to_s ) ,
2022-08-12 15:11:42 +00:00
desc : 'The array of scopes of the personal access token'
2020-11-16 12:09:05 +00:00
optional :expires_at , type : Date , desc : 'The expiration date in the format YEAR-MONTH-DAY of the personal access token'
end
post feature_category : :authentication_and_authorization do
response = :: PersonalAccessTokens :: CreateService . new (
current_user : current_user , target_user : target_user , params : declared_params ( include_missing : false )
) . execute
if response . success?
present response . payload [ :personal_access_token ] , with : Entities :: PersonalAccessTokenWithToken
else
render_api_error! ( response . message , response . http_status || :unprocessable_entity )
end
end
end
2016-12-27 16:26:57 +00:00
end
2012-06-29 10:46:01 +00:00
end
2012-09-21 11:49:28 +00:00
resource :user do
2017-07-04 12:19:48 +00:00
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
2022-06-03 09:08:43 +00:00
get feature_category : :users , urgency : :low do
2018-06-13 08:25:01 +00:00
entity =
if current_user . admin?
Entities :: UserWithAdmin
else
Entities :: UserPublic
end
2017-07-12 10:18:14 +00:00
2018-07-24 12:46:19 +00:00
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
2017-01-17 04:45:07 +00:00
params do
use :pagination
end
2020-10-26 18:08:27 +00:00
get " keys " , feature_category : :authentication_and_authorization do
2020-06-15 18:08:43 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get " keys/:key_id " , feature_category : :authentication_and_authorization do
2016-10-27 08:20:06 +00:00
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
2018-08-27 15:31:01 +00:00
# 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'
2020-06-04 00:08:17 +00:00
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
2020-10-26 18:08:27 +00:00
post " keys " , feature_category : :authentication_and_authorization do
2020-06-17 15:08:36 +00:00
key = :: Keys :: CreateService . new ( current_user , declared_params ( include_missing : false ) ) . execute
2013-02-20 11:10:51 +00:00
2020-06-17 15:08:36 +00:00
if key . persisted?
2012-09-21 11:49:28 +00:00
present key , with : Entities :: SSHKey
else
2014-08-18 18:09:09 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete " keys/:key_id " , feature_category : :authentication_and_authorization do
2016-10-27 08:20:06 +00:00
key = current_user . keys . find_by ( id : params [ :key_id ] )
not_found! ( 'Key' ) unless key
2020-06-18 12:09:25 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 13:40:08 +00:00
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'
2020-03-07 03:08:03 +00:00
success Entities :: GpgKey
2017-08-25 10:01:34 +00:00
end
params do
use :pagination
end
2020-10-26 18:08:27 +00:00
get 'gpg_keys' , feature_category : :authentication_and_authorization do
2020-03-07 03:08:03 +00:00
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'
2020-03-07 03:08:03 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get 'gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 10:01:34 +00:00
key = current_user . gpg_keys . find_by ( id : params [ :key_id ] )
not_found! ( 'GPG Key' ) unless key
2020-03-07 03:08:03 +00:00
present key , with : Entities :: GpgKey
2017-08-25 10:01:34 +00:00
end
2018-08-27 15:31:01 +00:00
# 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'
2020-03-07 03:08:03 +00:00
success Entities :: GpgKey
2017-08-25 10:01:34 +00:00
end
params do
requires :key , type : String , desc : 'The new GPG key'
end
2020-10-26 18:08:27 +00:00
post 'gpg_keys' , feature_category : :authentication_and_authorization do
2020-06-19 12:09:07 +00:00
key = :: GpgKeys :: CreateService . new ( current_user , declared_params ( include_missing : false ) ) . execute
2017-08-25 10:01:34 +00:00
2020-06-19 12:09:07 +00:00
if key . persisted?
2020-03-07 03:08:03 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
post 'gpg_keys/:key_id/revoke' , feature_category : :authentication_and_authorization do
2017-08-25 10:01:34 +00:00
key = current_user . gpg_keys . find_by ( id : params [ :key_id ] )
not_found! ( 'GPG Key' ) unless key
key . revoke
status :accepted
end
2018-08-27 15:31:01 +00:00
# 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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete 'gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 10:01:34 +00:00
key = current_user . gpg_keys . find_by ( id : params [ :key_id ] )
not_found! ( 'GPG Key' ) unless key
2020-06-23 12:09:20 +00:00
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
2018-08-27 15:31:01 +00:00
# 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
2017-01-17 04:45:07 +00:00
params do
use :pagination
end
2022-04-22 18:09:22 +00:00
get " emails " , feature_category : :users , urgency : :high do
2017-01-17 04:45:07 +00:00
present paginate ( current_user . emails ) , with : Entities :: Email
2015-07-29 13:40:08 +00:00
end
2021-05-07 18:10:21 +00:00
desc " Update a user's credit_card_validation " do
success Entities :: UserCreditCardValidations
end
params do
requires :user_id , type : String , desc : 'The ID or username of the user'
requires :credit_card_validated_at , type : DateTime , desc : 'The time when the user\'s credit card was validated'
2021-10-05 15:12:53 +00:00
requires :credit_card_expiration_month , type : Integer , desc : 'The month the credit card expires'
requires :credit_card_expiration_year , type : Integer , desc : 'The year the credit card expires'
requires :credit_card_holder_name , type : String , desc : 'The credit card holder name'
requires :credit_card_mask_number , type : String , desc : 'The last 4 digits of credit card number'
2021-10-25 18:12:16 +00:00
requires :credit_card_type , type : String , desc : 'The credit card network name'
2021-05-07 18:10:21 +00:00
end
2022-05-20 18:07:48 +00:00
put " :user_id/credit_card_validation " , urgency : :low , feature_category : :purchase do
2021-05-07 18:10:21 +00:00
authenticated_as_admin!
user = find_user ( params [ :user_id ] )
not_found! ( 'User' ) unless user
attrs = declared_params ( include_missing : false )
2022-01-19 18:14:01 +00:00
service = :: Users :: UpsertCreditCardValidationService . new ( attrs , user ) . execute
2021-05-07 18:10:21 +00:00
if service . success?
present user . credit_card_validation , with : Entities :: UserCreditCardValidations
else
render_api_error! ( '400 Bad Request' , 400 )
end
end
2021-04-02 21:09:22 +00:00
desc " Update the current user's preferences " do
success Entities :: UserPreferences
detail 'This feature was introduced in GitLab 13.10.'
end
params do
2021-05-27 06:10:47 +00:00
optional :view_diffs_file_by_file , type : Boolean , desc : 'Flag indicating the user sees only one file diff per page'
optional :show_whitespace_in_diffs , type : Boolean , desc : 'Flag indicating the user sees whitespace changes in diffs'
at_least_one_of :view_diffs_file_by_file , :show_whitespace_in_diffs
2021-04-02 21:09:22 +00:00
end
2022-04-22 09:09:00 +00:00
put " preferences " , feature_category : :users , urgency : :high do
2021-04-02 21:09:22 +00:00
authenticate!
preferences = current_user . user_preference
attrs = declared_params ( include_missing : false )
service = :: UserPreferences :: UpdateService . new ( current_user , attrs ) . execute
if service . success?
present preferences , with : Entities :: UserPreferences
else
render_api_error! ( '400 Bad Request' , 400 )
end
end
2021-06-09 03:10:22 +00:00
desc " Get the current user's preferences " do
success Entities :: UserPreferences
detail 'This feature was introduced in GitLab 14.0.'
end
get " preferences " , feature_category : :users do
present current_user . user_preference , with : Entities :: UserPreferences
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get " emails/:email_id " , feature_category : :users do
2016-10-27 08:20:06 +00:00
email = current_user . emails . find_by ( id : params [ :email_id ] )
not_found! ( 'Email' ) unless email
2015-07-29 13:40:08 +00:00
present email , with : Entities :: Email
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 13:40:08 +00:00
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
2020-10-26 18:08:27 +00:00
post " emails " , feature_category : :users do
2017-09-27 14:39:10 +00:00
email = Emails :: CreateService . new ( current_user , declared_params . merge ( user : current_user ) ) . execute
2015-07-29 13:40:08 +00:00
2017-06-22 13:55:05 +00:00
if email . errors . blank?
2015-07-29 13:40:08 +00:00
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
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
delete " emails/:email_id " , feature_category : :users do
2016-10-27 08:20:06 +00:00
email = current_user . emails . find_by ( id : params [ :email_id ] )
not_found! ( 'Email' ) unless email
2015-07-29 13:40:08 +00:00
2017-03-02 12:14:13 +00:00
destroy_conditionally! ( email ) do | email |
2017-10-05 10:48:22 +00:00
Emails :: DestroyService . new ( current_user , user : current_user ) . execute ( email )
2017-03-02 12:14:13 +00:00
end
2015-07-29 13:40:08 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2017-04-12 11:19:45 +00:00
desc 'Get a list of user activities'
params do
2017-03-27 13:43:10 +00:00
optional :from , type : DateTime , default : 6 . months . ago , desc : 'Date string in the format YEAR-MONTH-DAY'
2017-04-12 11:19:45 +00:00
use :pagination
end
2018-08-27 15:31:01 +00:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 18:08:27 +00:00
get " activities " , feature_category : :users do
2017-04-12 11:19:45 +00:00
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 )
2017-04-12 11:19:45 +00:00
2017-03-27 13:43:10 +00:00
present paginate ( activities ) , with : Entities :: UserActivity
2017-04-12 11:19:45 +00:00
end
2018-08-27 15:31:01 +00:00
# rubocop: enable CodeReuse/ActiveRecord
2018-07-13 15:52:31 +00:00
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 "
2020-10-29 18:09:11 +00:00
optional :availability , type : String , desc : " The availability of user to set "
2021-02-12 18:08:59 +00:00
optional :clear_status_after , type : String , desc : " Automatically clear emoji, message and availability fields after a certain time " , values : UserStatus :: CLEAR_STATUS_QUICK_OPTIONS . keys
2018-07-13 15:52:31 +00:00
end
2020-10-26 18:08:27 +00:00
put " status " , feature_category : :users do
2018-07-13 15:52:31 +00:00
forbidden! unless can? ( current_user , :update_user_status , current_user )
2021-02-23 18:10:40 +00:00
if :: Users :: SetStatusService . new ( current_user , declared_params ) . execute
2018-07-13 15:52:31 +00:00
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
2020-10-26 18:08:27 +00:00
get 'status' , feature_category : :users do
2018-07-13 15:52:31 +00:00
present current_user . status || { } , with : Entities :: UserStatus
end
2012-06-29 10:46:01 +00:00
end
end
end
2022-07-19 09:08:45 +00:00
API :: Users . prepend_mod