2018-09-29 18:34:47 -04:00
# frozen_string_literal: true
2013-05-14 08:33:31 -04:00
module API
2020-10-14 20:08:42 -04:00
class Users < :: API :: Base
2016-12-04 12:11:19 -05:00
include PaginationParams
2017-06-20 03:40:24 -04:00
include APIGuard
2017-12-22 10:54:55 -05:00
include Helpers :: CustomAttributes
2017-06-20 03:40:24 -04:00
2021-02-02 13:09:42 -05:00
allow_access_with_scope :read_user , if : - > ( request ) { request . get? || request . head? }
2016-12-04 12:11:19 -05:00
2020-10-26 14:08:27 -04:00
feature_category :users , [ '/users/:id/custom_attributes' , '/users/:id/custom_attributes/:key' ]
2022-04-21 11:10:09 -04:00
urgency :high , [ '/users/:id/custom_attributes' , '/users/:id/custom_attributes/:key' ]
2015-08-13 09:35:42 -04:00
resource :users , requirements : { uid : / [0-9]* / , id : / [0-9]* / } do
2017-09-28 12:49:42 -04:00
include CustomAttributesEndpoints
2017-07-04 08:19:48 -04:00
before do
authenticate_non_get!
end
2019-05-28 06:14:26 -04:00
helpers Helpers :: UsersHelpers
2016-10-27 04:20:06 -04:00
helpers do
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2017-09-21 10:10:33 -04:00
def find_user_by_id ( params )
2017-03-01 11:59:03 -05:00
id = params [ :user_id ] || params [ :id ]
User . find_by ( id : id ) || not_found! ( 'User' )
2017-02-23 12:47:06 -05:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-02-23 12:47:06 -05:00
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2018-02-06 08:37:52 -05:00
def reorder_users ( users )
if params [ :order_by ] && params [ :sort ]
2019-02-16 05:03:42 -05:00
users . reorder ( order_options_with_tie_breaker )
2018-02-06 08:37:52 -05:00
else
users
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2018-02-06 08:37:52 -05:00
2016-10-27 04:20:06 -04: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 02:44:33 -05:00
optional :extern_uid , type : String , desc : 'The external authentication provider UID'
2016-10-27 04:20:06 -04: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 11:27:26 -04:00
optional :public_email , type : String , desc : 'The public email of the user'
2016-10-27 04:20:06 -04: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'
2019-09-18 10:02:45 -04:00
# TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960
2019-09-10 12:24:10 -04:00
optional :avatar , type : File , desc : 'Avatar image for user' # rubocop:disable Scalability/FileUploads
2020-03-13 20:09:30 -04: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 16:08:48 -05:00
optional :private_profile , type : Boolean , desc : 'Flag indicating the user has a private profile'
2020-05-28 05:08:05 -04:00
optional :note , type : String , desc : 'Admin note for this user'
2021-02-25 01:10:51 -05:00
optional :view_diffs_file_by_file , type : Boolean , desc : 'Flag indicating the user sees only one file diff per page'
2016-10-27 04:20:06 -04:00
all_or_none_of :extern_uid , :provider
2019-03-25 10:33:16 -04:00
2019-05-28 06:14:26 -04:00
use :optional_params_ee
2016-10-27 04:20:06 -04:00
end
2018-02-06 08:37:52 -05:00
params :sort_params do
optional :order_by , type : String , values : %w[ id name username created_at updated_at ] ,
2020-11-16 07:09:05 -05:00
default : 'id' , desc : 'Return users ordered by a field'
2018-02-06 08:37:52 -05:00
optional :sort , type : String , values : %w[ asc desc ] , default : 'desc' ,
2020-11-16 07:09:05 -05:00
desc : 'Return users sorted in ascending and descending order'
2018-02-06 08:37:52 -05:00
end
2016-10-27 04:20:06 -04:00
end
desc 'Get the list of users' do
success Entities :: UserBasic
end
params do
2017-04-05 12:31:15 -04:00
# CE
2016-10-27 04:20:06 -04:00
optional :username , type : String , desc : 'Get a single user with a specific username'
2017-02-15 20:44:36 -05: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 04:20:06 -04: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 10:11:10 -05:00
optional :exclude_external , as : :non_external , type : Boolean , default : false , desc : 'Filters only non external users'
2016-10-27 04:20:06 -04:00
optional :blocked , type : Boolean , default : false , desc : 'Filters only blocked users'
2017-07-07 03:29:00 -04: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 05:09:46 -04:00
optional :without_projects , type : Boolean , default : false , desc : 'Filters only users without projects'
2020-08-31 11:10:41 -04:00
optional :exclude_internal , as : :non_internal , type : Boolean , default : false , desc : 'Filters only non internal users'
2022-03-30 20:08:33 -04:00
optional :without_project_bots , type : Boolean , default : false , desc : 'Filters users without project bots'
2021-01-18 07:10:41 -05:00
optional :admins , type : Boolean , default : false , desc : 'Filters only admin users'
2017-02-15 20:44:36 -05:00
all_or_none_of :extern_uid , :provider
2017-04-05 12:31:15 -04:00
2018-02-06 08:37:52 -05:00
use :sort_params
2016-12-04 12:11:19 -05:00
use :pagination
2017-12-22 10:54:55 -05:00
use :with_custom_attributes
2019-05-28 06:14:26 -04:00
use :optional_index_params_ee
2016-10-27 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2022-04-19 11:08:32 -04:00
get feature_category : :users , urgency : :default do
2021-02-24 10:11:10 -05:00
authenticated_as_admin! if params [ :extern_uid ] . present? && params [ :provider ] . present?
2017-02-15 20:44:36 -05:00
2017-07-07 10:09:30 -04:00
unless current_user & . admin?
2020-04-15 05:09:46 -04:00
params . except! ( :created_after , :created_before , :order_by , :sort , :two_factor , :without_projects )
2017-07-07 03:29:00 -04:00
end
2017-06-29 03:43:41 -04:00
authorized = can? ( current_user , :read_users_list )
2017-06-26 03:20:30 -04:00
2017-06-29 03:43:41 -04: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 03:20:30 -04:00
2017-06-29 03:43:41 -04:00
forbidden! ( " Not authorized to access /api/v4/users " ) unless authorized
2022-02-25 19:14:54 -05:00
users = UsersFinder . new ( current_user , params ) . execute
users = reorder_users ( users )
2017-06-29 03:43:41 -04:00
entity = current_user & . admin? ? Entities :: UserWithAdmin : Entities :: UserBasic
2022-03-22 08:07:28 -04:00
if entity == Entities :: UserWithAdmin
users = users . preload ( :identities , :u2f_registrations , :webauthn_registrations , :namespace )
end
2018-07-24 08:46:19 -04:00
users , options = with_custom_attributes ( users , { with : entity , current_user : current_user } )
2017-12-04 04:49:53 -05:00
2020-07-09 20:09:13 -04:00
users = users . preload ( :user_detail )
2017-12-22 10:54:55 -05:00
present paginate ( users ) , options
2012-06-29 06:46:01 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2012-06-29 06:46:01 -04:00
2016-10-27 04:20:06 -04:00
desc 'Get a single user' do
2017-08-11 08:08:20 -04:00
success Entities :: User
2016-10-27 04:20:06 -04:00
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
2017-12-22 10:54:55 -05:00
use :with_custom_attributes
2016-10-27 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2022-04-19 11:08:32 -04:00
get " :id " , feature_category : :users , urgency : :medium do
2021-09-30 14:11:31 -04:00
forbidden! ( 'Not authorized!' ) unless current_user
2022-03-04 07:13:07 -05: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 10:12:25 -05:00
end
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params [ :id ] )
2021-09-30 14:11:31 -04:00
2017-08-11 08:08:20 -04:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
2021-12-20 10:12:25 -05:00
opts = { with : current_user . admin? ? Entities :: UserDetailsWithAdmin : Entities :: User , current_user : current_user }
2017-12-22 10:54:55 -05:00
user , opts = with_custom_attributes ( user , opts )
2017-08-11 08:08:20 -04:00
present user , opts
2012-06-29 06:46:01 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2012-10-19 06:23:10 -04:00
2018-07-13 11:52:31 -04:00
desc " Get the status of a user "
params do
2019-01-31 05:13:23 -05:00
requires :user_id , type : String , desc : 'The ID or username of the user'
2018-07-13 11:52:31 -04:00
end
2022-04-19 11:08:32 -04:00
get " :user_id/status " , requirements : API :: USER_REQUIREMENTS , feature_category : :users , urgency : :high do
2019-01-31 05:13:23 -05:00
user = find_user ( params [ :user_id ] )
2021-09-30 14:11:31 -04:00
2018-07-13 11:52:31 -04:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
present user . status || { } , with : Entities :: UserStatus
end
2021-02-15 16:08:59 -05: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
if current_user . follow ( user )
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 14:11:31 -04:00
forbidden! ( 'Not authorized!' ) unless current_user
2021-02-15 16:08:59 -05: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 14:11:31 -04:00
forbidden! ( 'Not authorized!' ) unless current_user
2021-02-15 16:08:59 -05: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 04:20:06 -04:00
desc 'Create a user. Available only for admins.' do
2019-07-16 05:22:40 -04:00
success Entities :: UserWithAdmin
2016-10-27 04:20:06 -04:00
end
params do
requires :email , type : String , desc : 'The email of the user'
2017-02-03 09:49:27 -05: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 10:47:58 -05:00
optional :skip_confirmation , type : Boolean , desc : 'Flag indicating the account is confirmed'
2021-03-31 20:09:32 -04:00
at_least_one_of :password , :reset_password , :force_random_password
2016-10-27 04:20:06 -04:00
requires :name , type : String , desc : 'The name of the user'
requires :username , type : String , desc : 'The username of the user'
2019-06-27 15:41:51 -04:00
optional :force_random_password , type : Boolean , desc : 'Flag indicating a random password will be set'
2016-10-27 04:20:06 -04:00
use :optional_attributes
end
2020-10-26 14:08:27 -04:00
post feature_category : :users do
2012-10-02 05:46:01 -04:00
authenticated_as_admin!
2016-10-27 04:20:06 -04:00
2017-03-27 05:37:24 -04:00
params = declared_params ( include_missing : false )
2021-05-31 11:11:12 -04:00
user = :: Users :: AuthorizedCreateService . new ( current_user , params ) . execute
2017-02-03 09:49:27 -05:00
2017-03-27 05:37:24 -04:00
if user . persisted?
2019-07-16 05:22:40 -04:00
present user , with : Entities :: UserWithAdmin , current_user : current_user
2012-10-02 05:46:01 -04:00
else
2017-06-21 09:48:12 -04:00
conflict! ( 'Email has already been taken' ) if User
2018-10-18 05:06:44 -04:00
. by_any_email ( user . email . downcase )
. any?
2014-08-18 14:09:09 -04:00
2017-06-21 09:48:12 -04:00
conflict! ( 'Username has already been taken' ) if User
2018-10-18 05:06:44 -04:00
. by_username ( user . username )
. any?
2014-08-18 14:09:09 -04:00
render_validation_error! ( user )
2012-10-02 05:46:01 -04:00
end
end
2012-12-18 14:24:31 -05:00
2016-10-27 04:20:06 -04:00
desc 'Update a user. Available only for admins.' do
2019-07-16 05:22:40 -04:00
success Entities :: UserWithAdmin
2016-10-27 04:20:06 -04: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 10:47:58 -05:00
optional :skip_reconfirmation , type : Boolean , desc : 'Flag indicating the account skips the confirmation by email'
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
put " :id " , feature_category : :users do
2012-12-18 14:24:31 -05:00
authenticated_as_admin!
2013-02-20 06:10:51 -05:00
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params . delete ( :id ) )
2014-08-18 14:09:09 -04:00
not_found! ( 'User' ) unless user
2012-12-18 14:24:31 -05:00
2016-10-27 04:20:06 -04:00
conflict! ( 'Email has already been taken' ) if params [ :email ] &&
2018-10-18 05:06:44 -04:00
User . by_any_email ( params [ :email ] . downcase )
2020-03-23 05:09:42 -04:00
. where . not ( id : user . id ) . exists?
2014-08-18 14:09:09 -04:00
2016-10-27 04:20:06 -04:00
conflict! ( 'Username has already been taken' ) if params [ :username ] &&
2018-10-18 05:06:44 -04:00
User . by_username ( params [ :username ] )
2020-03-23 05:09:42 -04:00
. where . not ( id : user . id ) . exists?
2014-08-18 14:09:09 -04:00
2016-11-21 11:44:24 -05:00
user_params = declared_params ( include_missing : false )
2020-09-04 05:08:38 -04:00
admin_making_changes_for_another_user = ( current_user != user )
2015-09-22 17:26:59 -04:00
2020-09-04 05:08:38 -04: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 10:42:14 -04:00
if result [ :status ] == :success
2019-07-16 05:22:40 -04:00
present user , with : Entities :: UserWithAdmin , current_user : current_user
2012-12-18 14:24:31 -05:00
else
2014-08-18 14:09:09 -04:00
render_validation_error! ( user )
2012-12-18 14:24:31 -05:00
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2012-12-18 14:24:31 -05:00
2020-02-14 07:09:03 -05: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 14:08:27 -04:00
delete " :id/identities/:provider " , feature_category : :authentication_and_authorization do
2020-02-14 07:09:03 -05: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
2016-10-27 04:20:06 -04: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'
2020-06-03 20:08:17 -04: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 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post " :id/keys " , feature_category : :authentication_and_authorization do
2012-11-14 15:37:52 -05:00
authenticated_as_admin!
2014-08-18 14:09:09 -04:00
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params . delete ( :id ) )
not_found! ( 'User' ) unless user
2020-06-15 08:08:44 -04:00
key = :: Keys :: CreateService . new ( current_user , declared_params ( include_missing : false ) . merge ( user : user ) ) . execute
2016-10-27 04:20:06 -04:00
2020-06-15 08:08:44 -04:00
if key . persisted?
2012-11-14 15:37:52 -05:00
present key , with : Entities :: SSHKey
else
2014-08-18 14:09:09 -04:00
render_validation_error! ( key )
2012-11-14 15:37:52 -05:00
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2012-11-14 15:37:52 -05:00
2018-06-28 02:13:21 -04:00
desc 'Get the SSH keys of a specified user.' do
2016-10-27 04:20:06 -04:00
success Entities :: SSHKey
end
params do
2020-01-20 04:08:32 -05:00
requires :user_id , type : String , desc : 'The ID or username of the user'
2017-01-16 23:45:07 -05:00
use :pagination
2016-10-27 04:20:06 -04:00
end
2020-10-26 14:08:27 -04:00
get ':user_id/keys' , requirements : API :: USER_REQUIREMENTS , feature_category : :authentication_and_authorization do
2020-01-20 04:08:32 -05:00
user = find_user ( params [ :user_id ] )
2018-06-28 02:13:21 -04:00
not_found! ( 'User' ) unless user && can? ( current_user , :read_user , user )
2014-08-18 14:09:09 -04:00
2020-06-15 14:08:43 -04:00
keys = user . keys . preload_users
present paginate ( keys ) , with : Entities :: SSHKey
2014-04-15 10:39:46 -04:00
end
2022-03-03 07:14:02 -05: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 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete ':id/keys/:key_id' , feature_category : :authentication_and_authorization do
2014-04-15 10:39:46 -04:00
authenticated_as_admin!
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params [ :id ] )
2014-08-18 14:09:09 -04:00
not_found! ( 'User' ) unless user
2016-10-27 04:20:06 -04:00
key = user . keys . find_by ( id : params [ :key_id ] )
not_found! ( 'Key' ) unless key
2020-06-16 11:08:32 -04:00
destroy_conditionally! ( key ) do | key |
destroy_service = :: Keys :: DestroyService . new ( current_user )
destroy_service . execute ( key )
end
2014-04-15 10:39:46 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2014-04-15 10:39:46 -04:00
2017-08-25 06:24:41 -04: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-06 22:08:03 -05:00
success Entities :: GpgKey
2017-08-25 06:24:41 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post ':id/gpg_keys' , feature_category : :authentication_and_authorization do
2017-08-25 06:24:41 -04:00
authenticated_as_admin!
user = User . find_by ( id : params . delete ( :id ) )
not_found! ( 'User' ) unless user
2020-06-19 08:09:07 -04:00
key = :: GpgKeys :: CreateService . new ( user , declared_params ( include_missing : false ) ) . execute
2017-08-25 06:24:41 -04:00
2020-06-19 08:09:07 -04:00
if key . persisted?
2020-03-06 22:08:03 -05:00
present key , with : Entities :: GpgKey
2017-08-25 06:24:41 -04:00
else
render_validation_error! ( key )
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:24:41 -04:00
2020-09-29 20:09:53 -04:00
desc 'Get the GPG keys of a specified user.' do
2017-08-25 06:24:41 -04:00
detail 'This feature was added in GitLab 10.0'
2020-03-06 22:08:03 -05:00
success Entities :: GpgKey
2017-08-25 06:24:41 -04:00
end
params do
requires :id , type : Integer , desc : 'The ID of the user'
use :pagination
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get ':id/gpg_keys' , feature_category : :authentication_and_authorization do
2017-08-25 06:24:41 -04:00
user = User . find_by ( id : params [ :id ] )
not_found! ( 'User' ) unless user
2020-03-06 22:08:03 -05:00
present paginate ( user . gpg_keys ) , with : Entities :: GpgKey
2017-08-25 06:24:41 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:24:41 -04:00
2020-10-07 14:08:34 -04: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 14:08:27 -04:00
get ':id/gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2020-10-07 14:08:34 -04: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 06:24:41 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete ':id/gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 06:24:41 -04: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 08:08:47 -04:00
destroy_conditionally! ( key ) do | key |
destroy_service = :: GpgKeys :: DestroyService . new ( current_user )
destroy_service . execute ( key )
end
2017-08-25 06:24:41 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:24:41 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post ':id/gpg_keys/:key_id/revoke' , feature_category : :authentication_and_authorization do
2017-08-25 06:24:41 -04: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 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:24:41 -04:00
2016-10-27 04:20:06 -04: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 17:04:11 -04:00
optional :skip_confirmation , type : Boolean , desc : 'Skip confirmation of email and assume it is verified'
2016-10-27 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post " :id/emails " , feature_category : :users do
2015-07-29 09:40:08 -04:00
authenticated_as_admin!
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params . delete ( :id ) )
not_found! ( 'User' ) unless user
2017-09-27 10:39:10 -04:00
email = Emails :: CreateService . new ( current_user , declared_params ( include_missing : false ) . merge ( user : user ) ) . execute
2017-06-22 09:55:05 -04:00
if email . errors . blank?
2015-07-29 09:40:08 -04:00
present email , with : Entities :: Email
else
render_validation_error! ( email )
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 09:40:08 -04:00
2016-10-27 04:20:06 -04: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-16 23:45:07 -05:00
use :pagination
2016-10-27 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get ':id/emails' , feature_category : :users do
2015-07-29 09:40:08 -04:00
authenticated_as_admin!
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params [ :id ] )
2015-07-29 09:40:08 -04:00
not_found! ( 'User' ) unless user
2017-01-16 23:45:07 -05:00
present paginate ( user . emails ) , with : Entities :: Email
2015-07-29 09:40:08 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 09:40:08 -04:00
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete ':id/emails/:email_id' , feature_category : :users do
2015-07-29 09:40:08 -04:00
authenticated_as_admin!
2016-10-27 04:20:06 -04:00
user = User . find_by ( id : params [ :id ] )
2015-07-29 09:40:08 -04:00
not_found! ( 'User' ) unless user
2016-10-27 04:20:06 -04:00
email = user . emails . find_by ( id : params [ :email_id ] )
not_found! ( 'Email' ) unless email
2015-07-29 09:40:08 -04:00
2017-03-02 07:14:13 -05:00
destroy_conditionally! ( email ) do | email |
2017-10-05 06:48:22 -04:00
Emails :: DestroyService . new ( current_user , user : user ) . execute ( email )
2017-03-02 07:14:13 -05:00
end
2015-07-29 09:40:08 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 09:40:08 -04:00
2016-10-27 04:20:06 -04: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 12:14:39 -04:00
optional :hard_delete , type : Boolean , desc : " Whether to remove a user's contributions "
2016-10-27 04:20:06 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete " :id " , feature_category : :users do
2012-12-18 14:24:31 -05:00
authenticated_as_admin!
2017-03-01 08:35:48 -05:00
2014-01-19 13:55:59 -05:00
user = User . find_by ( id : params [ :id ] )
2016-10-27 04:20:06 -04:00
not_found! ( 'User' ) unless user
2019-12-11 19:07:43 -05: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 14:24:31 -05:00
2017-03-02 07:14:13 -05:00
destroy_conditionally! ( user ) do
user . delete_async ( deleted_by : current_user , params : params )
end
2012-12-18 14:24:31 -05:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-04-28 12:02:44 -04:00
2019-10-09 20:06:44 -04: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 14:08:27 -04:00
post ':id/activate' , feature_category : :authentication_and_authorization do
2019-10-09 20:06:44 -04: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 07:09:11 -05: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 05:11:16 -04: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-09 20:06:44 -04: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 14:08:27 -04:00
post ':id/deactivate' , feature_category : :authentication_and_authorization do
2019-10-09 20:06:44 -04: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 02:08:33 -04:00
forbidden! ( 'An internal user cannot be deactivated by the API' ) if user . internal?
2019-10-09 20:06:44 -04:00
forbidden! ( " The user you are trying to deactivate has been active in the past #{ :: User :: MINIMUM_INACTIVE_DAYS } days and cannot be deactivated " )
end
2020-10-14 02:08:33 -04:00
if user . deactivate
true
else
render_api_error! ( user . errors . full_messages , 400 )
end
2019-10-09 20:06:44 -04:00
end
# rubocop: enable CodeReuse/ActiveRecord
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post ':id/block' , feature_category : :authentication_and_authorization do
2015-04-28 12:02:44 -04:00
authenticated_as_admin!
user = User . find_by ( id : params [ :id ] )
2016-10-27 04:20:06 -04:00
not_found! ( 'User' ) unless user
2015-04-28 12:02:44 -04:00
2020-03-04 07:07:52 -05:00
if user . ldap_blocked?
2015-12-30 13:52:02 -05:00
forbidden! ( 'LDAP blocked users cannot be modified by the API' )
2022-03-09 01:07:38 -05:00
elsif current_user == user
forbidden! ( 'The API initiating user cannot be blocked by the API' )
2015-04-28 12:02:44 -04:00
end
2020-03-04 07:07:52 -05: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 12:02:44 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-04-28 12:02:44 -04:00
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post ':id/unblock' , feature_category : :authentication_and_authorization do
2015-04-28 12:02:44 -04:00
authenticated_as_admin!
user = User . find_by ( id : params [ :id ] )
2016-10-27 04:20:06 -04:00
not_found! ( 'User' ) unless user
2015-04-28 12:02:44 -04:00
2016-10-27 04:20:06 -04:00
if user . ldap_blocked?
2015-12-30 13:52:02 -05:00
forbidden! ( 'LDAP blocked users cannot be unblocked by the API' )
2019-10-09 20:06:44 -04:00
elsif user . deactivated?
forbidden! ( 'Deactivated users cannot be unblocked by the API' )
2016-01-12 09:29:10 -05:00
else
user . activate
2015-04-28 12:02:44 -04:00
end
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2016-10-10 07:35:26 -04:00
2021-08-26 05:11:15 -04: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 10:08:48 -05: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 11:10:09 -04:00
get " :user_id/memberships " , feature_category : :users , urgency : :high do
2020-01-22 10:08:48 -05: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 11:26:57 -05:00
params do
2017-03-01 11:59:03 -05: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 10:10:33 -04:00
user = find_user_by_id ( params )
2017-03-01 11:59:03 -05:00
PersonalAccessTokensFinder . new ( { user : user , impersonation : true } . merge ( options ) )
end
def find_impersonation_token
2018-10-26 10:47:03 -04:00
finder . find_by_id ( declared_params [ :impersonation_token_id ] ) || not_found! ( 'Impersonation Token' )
2017-03-01 11:59:03 -05:00
end
2017-02-27 13:56:54 -05:00
end
2016-12-27 11:26:57 -05:00
2017-03-01 11:59:03 -05:00
before { authenticated_as_admin! }
desc 'Retrieve impersonation tokens. Available only for admins.' do
2017-02-09 10:21:09 -05:00
detail 'This feature was introduced in GitLab 9.0'
2017-02-23 12:47:06 -05:00
success Entities :: ImpersonationToken
2017-02-09 10:21:09 -05:00
end
params do
2017-02-27 13:56:54 -05:00
use :pagination
2017-03-01 11:59:03 -05:00
optional :state , type : String , default : 'all' , values : %w[ all active inactive ] , desc : 'Filters (all|active|inactive) impersonation_tokens'
2017-02-09 10:21:09 -05:00
end
2021-09-28 08:11:10 -04:00
get feature_category : :authentication_and_authorization do
2020-10-26 14:08:27 -04:00
present paginate ( finder ( declared_params ( include_missing : false ) ) . execute ) , with : Entities :: ImpersonationToken
end
2016-12-27 11:26:57 -05:00
2017-03-01 11:59:03 -05:00
desc 'Create a impersonation token. Available only for admins.' do
2017-02-09 10:21:09 -05:00
detail 'This feature was introduced in GitLab 9.0'
2018-11-08 10:03:56 -05:00
success Entities :: ImpersonationTokenWithToken
2017-02-09 10:21:09 -05:00
end
params do
2017-03-01 11:59:03 -05: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'
optional :scopes , type : Array , desc : 'The array of scopes of the impersonation token'
2017-02-09 10:21:09 -05:00
end
2020-10-26 14:08:27 -04:00
post feature_category : :authentication_and_authorization do
2017-03-01 11:59:03 -05:00
impersonation_token = finder . build ( declared_params ( include_missing : false ) )
2017-02-09 10:21:09 -05:00
2017-03-01 11:59:03 -05:00
if impersonation_token . save
2018-11-08 10:03:56 -05:00
present impersonation_token , with : Entities :: ImpersonationTokenWithToken
2017-02-09 10:21:09 -05:00
else
2017-03-01 11:59:03 -05:00
render_validation_error! ( impersonation_token )
2017-02-09 10:21:09 -05:00
end
end
2016-12-27 11:26:57 -05:00
2017-03-01 11:59:03 -05:00
desc 'Retrieve impersonation token. Available only for admins.' do
2017-02-09 10:21:09 -05:00
detail 'This feature was introduced in GitLab 9.0'
2017-02-23 12:47:06 -05:00
success Entities :: ImpersonationToken
2017-02-09 10:21:09 -05:00
end
params do
2017-03-01 11:59:03 -05:00
requires :impersonation_token_id , type : Integer , desc : 'The ID of the impersonation token'
2017-02-09 10:21:09 -05:00
end
2020-10-26 14:08:27 -04:00
get ':impersonation_token_id' , feature_category : :authentication_and_authorization do
2017-03-01 11:59:03 -05:00
present find_impersonation_token , with : Entities :: ImpersonationToken
2017-02-09 10:21:09 -05:00
end
2016-12-27 11:26:57 -05:00
2017-03-01 11:59:03 -05:00
desc 'Revoke a impersonation token. Available only for admins.' do
2017-02-09 10:21:09 -05:00
detail 'This feature was introduced in GitLab 9.0'
end
params do
2017-03-01 11:59:03 -05:00
requires :impersonation_token_id , type : Integer , desc : 'The ID of the impersonation token'
2017-02-09 10:21:09 -05:00
end
2020-10-26 14:08:27 -04:00
delete ':impersonation_token_id' , feature_category : :authentication_and_authorization do
2017-08-24 04:41:54 -04:00
token = find_impersonation_token
destroy_conditionally! ( token ) do
token . revoke!
end
2017-02-09 10:21:09 -05:00
end
end
2020-11-16 07:09:05 -05: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 ) ,
desc : 'The array of scopes of the personal access token'
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 11:26:57 -05:00
end
2012-06-29 06:46:01 -04:00
end
2012-09-21 07:49:28 -04:00
resource :user do
2017-07-04 08:19:48 -04:00
before do
authenticate!
end
2018-06-13 04:25:01 -04: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-04-19 11:08:32 -04:00
get feature_category : :users , urgency : :medium do
2018-06-13 04:25:01 -04:00
entity =
if current_user . admin?
Entities :: UserWithAdmin
else
Entities :: UserPublic
end
2017-07-12 06:18:14 -04:00
2018-07-24 08:46:19 -04:00
present current_user , with : entity , current_user : current_user
2018-06-13 04:25:01 -04:00
end
2012-09-21 07:49:28 -04:00
end
2016-10-27 04:20:06 -04:00
desc " Get the currently authenticated user's SSH keys " do
success Entities :: SSHKey
end
2017-01-16 23:45:07 -05:00
params do
use :pagination
end
2020-10-26 14:08:27 -04:00
get " keys " , feature_category : :authentication_and_authorization do
2020-06-15 14:08:43 -04:00
keys = current_user . keys . preload_users
present paginate ( keys ) , with : Entities :: SSHKey
2012-09-21 07:49:28 -04:00
end
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get " keys/:key_id " , feature_category : :authentication_and_authorization do
2016-10-27 04:20:06 -04:00
key = current_user . keys . find_by ( id : params [ :key_id ] )
not_found! ( 'Key' ) unless key
2012-09-21 07:49:28 -04:00
present key , with : Entities :: SSHKey
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2012-09-21 07:49:28 -04:00
2016-10-27 04:20:06 -04: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-03 20:08:17 -04: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 04:20:06 -04:00
end
2020-10-26 14:08:27 -04:00
post " keys " , feature_category : :authentication_and_authorization do
2020-06-17 11:08:36 -04:00
key = :: Keys :: CreateService . new ( current_user , declared_params ( include_missing : false ) ) . execute
2013-02-20 06:10:51 -05:00
2020-06-17 11:08:36 -04:00
if key . persisted?
2012-09-21 07:49:28 -04:00
present key , with : Entities :: SSHKey
else
2014-08-18 14:09:09 -04:00
render_validation_error! ( key )
2012-09-21 07:49:28 -04:00
end
end
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete " keys/:key_id " , feature_category : :authentication_and_authorization do
2016-10-27 04:20:06 -04:00
key = current_user . keys . find_by ( id : params [ :key_id ] )
not_found! ( 'Key' ) unless key
2020-06-18 08:09:25 -04:00
destroy_conditionally! ( key ) do | key |
destroy_service = :: Keys :: DestroyService . new ( current_user )
destroy_service . execute ( key )
end
2012-09-21 07:49:28 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 09:40:08 -04:00
2017-08-25 06:01:34 -04:00
desc " Get the currently authenticated user's GPG keys " do
detail 'This feature was added in GitLab 10.0'
2020-03-06 22:08:03 -05:00
success Entities :: GpgKey
2017-08-25 06:01:34 -04:00
end
params do
use :pagination
end
2020-10-26 14:08:27 -04:00
get 'gpg_keys' , feature_category : :authentication_and_authorization do
2020-03-06 22:08:03 -05:00
present paginate ( current_user . gpg_keys ) , with : Entities :: GpgKey
2017-08-25 06:01:34 -04: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-06 22:08:03 -05:00
success Entities :: GpgKey
2017-08-25 06:01:34 -04:00
end
params do
requires :key_id , type : Integer , desc : 'The ID of the GPG key'
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get 'gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 06:01:34 -04:00
key = current_user . gpg_keys . find_by ( id : params [ :key_id ] )
not_found! ( 'GPG Key' ) unless key
2020-03-06 22:08:03 -05:00
present key , with : Entities :: GpgKey
2017-08-25 06:01:34 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:01:34 -04:00
desc 'Add a new GPG key to the currently authenticated user' do
detail 'This feature was added in GitLab 10.0'
2020-03-06 22:08:03 -05:00
success Entities :: GpgKey
2017-08-25 06:01:34 -04:00
end
params do
requires :key , type : String , desc : 'The new GPG key'
end
2020-10-26 14:08:27 -04:00
post 'gpg_keys' , feature_category : :authentication_and_authorization do
2020-06-19 08:09:07 -04:00
key = :: GpgKeys :: CreateService . new ( current_user , declared_params ( include_missing : false ) ) . execute
2017-08-25 06:01:34 -04:00
2020-06-19 08:09:07 -04:00
if key . persisted?
2020-03-06 22:08:03 -05:00
present key , with : Entities :: GpgKey
2017-08-25 06:01:34 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
post 'gpg_keys/:key_id/revoke' , feature_category : :authentication_and_authorization do
2017-08-25 06:01:34 -04: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 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:01:34 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete 'gpg_keys/:key_id' , feature_category : :authentication_and_authorization do
2017-08-25 06:01:34 -04:00
key = current_user . gpg_keys . find_by ( id : params [ :key_id ] )
not_found! ( 'GPG Key' ) unless key
2020-06-23 08:09:20 -04:00
destroy_conditionally! ( key ) do | key |
destroy_service = :: GpgKeys :: DestroyService . new ( current_user )
destroy_service . execute ( key )
end
2017-08-25 06:01:34 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-08-25 06:01:34 -04:00
2016-10-27 04:20:06 -04:00
desc " Get the currently authenticated user's email addresses " do
success Entities :: Email
end
2017-01-16 23:45:07 -05:00
params do
use :pagination
end
2022-04-22 14:09:22 -04:00
get " emails " , feature_category : :users , urgency : :high do
2017-01-16 23:45:07 -05:00
present paginate ( current_user . emails ) , with : Entities :: Email
2015-07-29 09:40:08 -04:00
end
2021-05-07 14:10:21 -04: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 11:12:53 -04: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 14:12:16 -04:00
requires :credit_card_type , type : String , desc : 'The credit card network name'
2021-05-07 14:10:21 -04:00
end
2022-04-06 11:08:23 -04:00
put " :user_id/credit_card_validation " , feature_category : :purchase do
2021-05-07 14:10:21 -04:00
authenticated_as_admin!
user = find_user ( params [ :user_id ] )
not_found! ( 'User' ) unless user
attrs = declared_params ( include_missing : false )
2022-01-19 13:14:01 -05:00
service = :: Users :: UpsertCreditCardValidationService . new ( attrs , user ) . execute
2021-05-07 14:10:21 -04: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 17:09:22 -04: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 02:10:47 -04: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 17:09:22 -04:00
end
2022-04-22 05:09:00 -04:00
put " preferences " , feature_category : :users , urgency : :high do
2021-04-02 17:09:22 -04: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-08 23:10:22 -04: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 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get " emails/:email_id " , feature_category : :users do
2016-10-27 04:20:06 -04:00
email = current_user . emails . find_by ( id : params [ :email_id ] )
not_found! ( 'Email' ) unless email
2015-07-29 09:40:08 -04:00
present email , with : Entities :: Email
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2015-07-29 09:40:08 -04:00
2016-10-27 04:20:06 -04: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 14:08:27 -04:00
post " emails " , feature_category : :users do
2017-09-27 10:39:10 -04:00
email = Emails :: CreateService . new ( current_user , declared_params . merge ( user : current_user ) ) . execute
2015-07-29 09:40:08 -04:00
2017-06-22 09:55:05 -04:00
if email . errors . blank?
2015-07-29 09:40:08 -04:00
present email , with : Entities :: Email
else
render_validation_error! ( email )
end
end
2016-10-27 04:20:06 -04: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 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
delete " emails/:email_id " , feature_category : :users do
2016-10-27 04:20:06 -04:00
email = current_user . emails . find_by ( id : params [ :email_id ] )
not_found! ( 'Email' ) unless email
2015-07-29 09:40:08 -04:00
2017-03-02 07:14:13 -05:00
destroy_conditionally! ( email ) do | email |
2017-10-05 06:48:22 -04:00
Emails :: DestroyService . new ( current_user , user : current_user ) . execute ( email )
2017-03-02 07:14:13 -05:00
end
2015-07-29 09:40:08 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2017-04-12 07:19:45 -04:00
desc 'Get a list of user activities'
params do
2017-03-27 09:43:10 -04:00
optional :from , type : DateTime , default : 6 . months . ago , desc : 'Date string in the format YEAR-MONTH-DAY'
2017-04-12 07:19:45 -04:00
use :pagination
end
2018-08-27 11:31:01 -04:00
# rubocop: disable CodeReuse/ActiveRecord
2020-10-26 14:08:27 -04:00
get " activities " , feature_category : :users do
2017-04-12 07:19:45 -04:00
authenticated_as_admin!
2017-06-21 09:48:12 -04:00
activities = User
. where ( User . arel_table [ :last_activity_on ] . gteq ( params [ :from ] ) )
. reorder ( last_activity_on : :asc )
2017-04-12 07:19:45 -04:00
2017-03-27 09:43:10 -04:00
present paginate ( activities ) , with : Entities :: UserActivity
2017-04-12 07:19:45 -04:00
end
2018-08-27 11:31:01 -04:00
# rubocop: enable CodeReuse/ActiveRecord
2018-07-13 11:52:31 -04: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 14:09:11 -04:00
optional :availability , type : String , desc : " The availability of user to set "
2021-02-12 13:08:59 -05: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 11:52:31 -04:00
end
2020-10-26 14:08:27 -04:00
put " status " , feature_category : :users do
2018-07-13 11:52:31 -04:00
forbidden! unless can? ( current_user , :update_user_status , current_user )
2021-02-23 13:10:40 -05:00
if :: Users :: SetStatusService . new ( current_user , declared_params ) . execute
2018-07-13 11:52:31 -04: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 14:08:27 -04:00
get 'status' , feature_category : :users do
2018-07-13 11:52:31 -04:00
present current_user . status || { } , with : Entities :: UserStatus
end
2012-06-29 06:46:01 -04:00
end
end
end