2015-12-05 17:13:13 -05:00
// Copyright 2015 The Gogs Authors. All rights reserved.
2019-01-24 04:00:19 +05:30
// Copyright 2019 The Gitea Authors. All rights reserved.
2022-11-27 13:20:29 -05:00
// SPDX-License-Identifier: MIT
2015-12-05 17:13:13 -05:00
package admin
import (
2019-10-14 22:24:26 +07:00
"errors"
2020-02-03 17:46:33 +01:00
"fmt"
2019-12-20 18:07:12 +01:00
"net/http"
2019-10-14 22:24:26 +07:00
2021-12-10 16:14:24 +08:00
asymkey_model "code.gitea.io/gitea/models/asymkey"
2022-01-02 21:12:35 +08:00
"code.gitea.io/gitea/models/auth"
2021-11-24 17:49:20 +08:00
"code.gitea.io/gitea/models/db"
2024-12-20 10:05:29 -08:00
org_model "code.gitea.io/gitea/models/organization"
packages_model "code.gitea.io/gitea/models/packages"
repo_model "code.gitea.io/gitea/models/repo"
2021-11-11 15:03:30 +08:00
user_model "code.gitea.io/gitea/models/user"
2023-02-19 07:35:20 +00:00
"code.gitea.io/gitea/modules/auth/password"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/modules/log"
2024-02-04 14:29:09 +01:00
"code.gitea.io/gitea/modules/optional"
2021-12-17 02:03:39 +00:00
"code.gitea.io/gitea/modules/setting"
2019-05-11 18:21:34 +08:00
api "code.gitea.io/gitea/modules/structs"
2023-02-16 17:32:01 +01:00
"code.gitea.io/gitea/modules/timeutil"
2021-01-26 23:36:53 +08:00
"code.gitea.io/gitea/modules/web"
2016-11-10 17:24:48 +01:00
"code.gitea.io/gitea/routers/api/v1/user"
2020-01-24 19:00:29 +00:00
"code.gitea.io/gitea/routers/api/v1/utils"
2021-12-10 16:14:24 +08:00
asymkey_service "code.gitea.io/gitea/services/asymkey"
2024-02-27 15:12:22 +08:00
"code.gitea.io/gitea/services/context"
2022-12-29 03:57:15 +01:00
"code.gitea.io/gitea/services/convert"
2019-09-24 13:02:49 +08:00
"code.gitea.io/gitea/services/mailer"
2021-11-18 18:42:27 +01:00
user_service "code.gitea.io/gitea/services/user"
2015-12-05 17:13:13 -05:00
)
2024-04-16 14:13:00 +09:00
func parseAuthSource ( ctx * context . APIContext , u * user_model . User , sourceID int64 ) {
2015-12-05 17:13:13 -05:00
if sourceID == 0 {
return
}
2023-10-11 06:24:07 +02:00
source , err := auth . GetSourceByID ( ctx , sourceID )
2015-12-05 17:13:13 -05:00
if err != nil {
2022-01-02 21:12:35 +08:00
if auth . IsErrSourceNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , err )
2015-12-05 17:13:13 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-05 17:13:13 -05:00
}
return
}
u . LoginType = source . Type
u . LoginSource = source . ID
}
2017-11-12 23:02:25 -08:00
// CreateUser create a user
2021-01-26 23:36:53 +08:00
func CreateUser ( ctx * context . APIContext ) {
2017-11-12 23:02:25 -08:00
// swagger:operation POST /admin/users admin adminCreateUser
// ---
// summary: Create a user
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/CreateUserOption"
// responses:
// "201":
// "$ref": "#/responses/User"
2019-12-20 18:07:12 +01:00
// "400":
// "$ref": "#/responses/error"
2020-01-09 12:56:32 +01:00
// "403":
// "$ref": "#/responses/forbidden"
2017-11-12 23:02:25 -08:00
// "422":
// "$ref": "#/responses/validationError"
2022-03-26 10:04:22 +01:00
2021-01-26 23:36:53 +08:00
form := web . GetForm ( ctx ) . ( * api . CreateUserOption )
2021-06-26 22:53:14 +03:00
2021-11-24 17:49:20 +08:00
u := & user_model . User {
2019-02-27 13:37:57 -06:00
Name : form . Username ,
FullName : form . FullName ,
Email : form . Email ,
Passwd : form . Password ,
MustChangePassword : true ,
2022-01-02 21:12:35 +08:00
LoginType : auth . Plain ,
2024-04-16 14:13:00 +09:00
LoginName : form . LoginName ,
2019-02-27 13:37:57 -06:00
}
if form . MustChangePassword != nil {
u . MustChangePassword = * form . MustChangePassword
2015-12-05 17:13:13 -05:00
}
2024-04-16 14:13:00 +09:00
parseAuthSource ( ctx , u , form . SourceID )
2015-12-05 17:13:13 -05:00
if ctx . Written ( ) {
return
}
2023-12-19 10:32:45 +08:00
if u . LoginType == auth . Plain {
if len ( form . Password ) < setting . MinPasswordLength {
err := errors . New ( "PasswordIsRequired" )
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2023-12-19 10:32:45 +08:00
return
}
if ! password . IsComplexEnough ( form . Password ) {
err := errors . New ( "PasswordComplexity" )
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2023-12-19 10:32:45 +08:00
return
}
2024-02-04 14:29:09 +01:00
if err := password . IsPwned ( ctx , form . Password ) ; err != nil {
if password . IsErrIsPwnedRequest ( err ) {
2023-12-19 10:32:45 +08:00
log . Error ( err . Error ( ) )
}
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , errors . New ( "PasswordPwned" ) )
2023-12-19 10:32:45 +08:00
return
2020-09-08 17:06:39 -05:00
}
}
2021-06-26 22:53:14 +03:00
2022-04-29 21:38:11 +02:00
overwriteDefault := & user_model . CreateUserOverwriteOptions {
2024-02-23 03:18:33 +01:00
IsActive : optional . Some ( true ) ,
IsRestricted : optional . FromPtr ( form . Restricted ) ,
2022-04-29 21:38:11 +02:00
}
2021-06-26 22:53:14 +03:00
if form . Visibility != "" {
2022-04-29 21:38:11 +02:00
visibility := api . VisibilityModes [ form . Visibility ]
overwriteDefault . Visibility = & visibility
2021-06-26 22:53:14 +03:00
}
2023-02-16 17:32:01 +01:00
// Update the user creation timestamp. This can only be done after the user
// record has been inserted into the database; the insert intself will always
// set the creation timestamp to "now".
if form . Created != nil {
u . CreatedUnix = timeutil . TimeStamp ( form . Created . Unix ( ) )
u . UpdatedUnix = u . CreatedUnix
}
2024-09-09 17:05:16 -04:00
if err := user_model . AdminCreateUser ( ctx , u , & user_model . Meta { } , overwriteDefault ) ; err != nil {
2021-11-24 17:49:20 +08:00
if user_model . IsErrUserAlreadyExist ( err ) ||
2021-11-11 15:03:30 +08:00
user_model . IsErrEmailAlreadyUsed ( err ) ||
2021-11-24 17:49:20 +08:00
db . IsErrNameReserved ( err ) ||
db . IsErrNameCharsNotAllowed ( err ) ||
2022-03-15 01:39:54 +08:00
user_model . IsErrEmailCharIsNotSupported ( err ) ||
2021-11-11 15:03:30 +08:00
user_model . IsErrEmailInvalid ( err ) ||
2021-11-24 17:49:20 +08:00
db . IsErrNamePatternNotAllowed ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , err )
2015-12-05 17:13:13 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-05 17:13:13 -05:00
}
return
}
2024-03-11 14:07:36 +08:00
if ! user_model . IsEmailDomainAllowed ( u . Email ) {
ctx . Resp . Header ( ) . Add ( "X-Gitea-Warning" , fmt . Sprintf ( "the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST" , u . Email ) )
}
2022-03-22 08:03:22 +01:00
log . Trace ( "Account created by admin (%s): %s" , ctx . Doer . Name , u . Name )
2015-12-05 17:13:13 -05:00
2016-07-16 00:36:39 +08:00
// Send email notification.
2019-09-24 13:02:49 +08:00
if form . SendNotify {
2021-04-02 12:25:13 +02:00
mailer . SendRegisterNotifyMail ( u )
2015-12-05 17:13:13 -05:00
}
2023-02-15 21:37:34 +08:00
ctx . JSON ( http . StatusCreated , convert . ToUser ( ctx , u , ctx . Doer ) )
2015-12-05 17:13:13 -05:00
}
2016-11-24 15:04:31 +08:00
// EditUser api for modifying a user's information
2021-01-26 23:36:53 +08:00
func EditUser ( ctx * context . APIContext ) {
2017-11-12 23:02:25 -08:00
// swagger:operation PATCH /admin/users/{username} admin adminEditUser
// ---
// summary: Edit an existing user
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: username
// in: path
2025-06-30 06:17:45 +02:00
// description: username of the user whose data is to be edited
2017-11-12 23:02:25 -08:00
// type: string
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditUserOption"
// responses:
// "200":
// "$ref": "#/responses/User"
2024-01-15 15:51:43 +09:00
// "400":
// "$ref": "#/responses/error"
2017-11-12 23:02:25 -08:00
// "403":
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
2022-03-26 10:04:22 +01:00
2021-01-26 23:36:53 +08:00
form := web . GetForm ( ctx ) . ( * api . EditUserOption )
2015-12-05 17:13:13 -05:00
2024-02-04 14:29:09 +01:00
authOpts := & user_service . UpdateAuthOptions {
LoginSource : optional . FromNonDefault ( form . SourceID ) ,
LoginName : optional . Some ( form . LoginName ) ,
Password : optional . FromNonDefault ( form . Password ) ,
MustChangePassword : optional . FromPtr ( form . MustChangePassword ) ,
ProhibitLogin : optional . FromPtr ( form . ProhibitLogin ) ,
2015-12-05 17:13:13 -05:00
}
2024-02-04 14:29:09 +01:00
if err := user_service . UpdateAuth ( ctx , ctx . ContextUser , authOpts ) ; err != nil {
switch {
case errors . Is ( err , password . ErrMinLength ) :
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , fmt . Errorf ( "password must be at least %d characters" , setting . MinPasswordLength ) )
2024-02-04 14:29:09 +01:00
case errors . Is ( err , password . ErrComplexity ) :
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2024-02-04 14:29:09 +01:00
case errors . Is ( err , password . ErrIsPwned ) , password . IsErrIsPwnedRequest ( err ) :
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2024-02-04 14:29:09 +01:00
default :
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2021-01-10 19:05:18 +01:00
}
2024-02-04 14:29:09 +01:00
return
2015-12-05 17:13:13 -05:00
}
2020-11-20 02:56:42 +01:00
if form . Email != nil {
2025-12-04 00:05:13 -08:00
if err := user_service . ReplacePrimaryEmailAddress ( ctx , ctx . ContextUser , * form . Email ) ; err != nil {
2024-02-04 14:29:09 +01:00
switch {
case user_model . IsErrEmailCharIsNotSupported ( err ) , user_model . IsErrEmailInvalid ( err ) :
2025-12-04 00:05:13 -08:00
if ! user_model . IsEmailDomainAllowed ( * form . Email ) {
err = fmt . Errorf ( "the domain of user email %s conflicts with EMAIL_DOMAIN_ALLOWLIST or EMAIL_DOMAIN_BLOCKLIST" , * form . Email )
}
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2024-02-04 14:29:09 +01:00
case user_model . IsErrEmailAlreadyUsed ( err ) :
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2024-02-04 14:29:09 +01:00
default :
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2024-02-04 14:29:09 +01:00
}
2024-01-15 15:51:43 +09:00
return
}
2021-02-18 09:25:35 +01:00
}
2015-12-05 17:13:13 -05:00
2024-02-04 14:29:09 +01:00
opts := & user_service . UpdateOptions {
FullName : optional . FromPtr ( form . FullName ) ,
Website : optional . FromPtr ( form . Website ) ,
Location : optional . FromPtr ( form . Location ) ,
Description : optional . FromPtr ( form . Description ) ,
IsActive : optional . FromPtr ( form . Active ) ,
2025-06-10 04:57:45 +08:00
IsAdmin : user_service . UpdateOptionFieldFromPtr ( form . Admin ) ,
2025-07-11 07:17:28 +08:00
Visibility : optional . FromMapLookup ( api . VisibilityModes , form . Visibility ) ,
2024-02-04 14:29:09 +01:00
AllowGitHook : optional . FromPtr ( form . AllowGitHook ) ,
AllowImportLocal : optional . FromPtr ( form . AllowImportLocal ) ,
MaxRepoCreation : optional . FromPtr ( form . MaxRepoCreation ) ,
AllowCreateOrganization : optional . FromPtr ( form . AllowCreateOrganization ) ,
IsRestricted : optional . FromPtr ( form . Restricted ) ,
}
if err := user_service . UpdateUser ( ctx , ctx . ContextUser , opts ) ; err != nil {
2024-12-20 10:05:29 -08:00
if user_model . IsErrDeleteLastAdminUser ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusBadRequest , err )
2015-12-05 17:13:13 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-05 17:13:13 -05:00
}
return
}
2024-02-04 14:29:09 +01:00
2022-03-26 10:04:22 +01:00
log . Trace ( "Account profile updated by admin (%s): %s" , ctx . Doer . Name , ctx . ContextUser . Name )
2015-12-05 17:13:13 -05:00
2023-02-15 21:37:34 +08:00
ctx . JSON ( http . StatusOK , convert . ToUser ( ctx , ctx . ContextUser , ctx . Doer ) )
2015-12-05 17:13:13 -05:00
}
2016-11-24 15:04:31 +08:00
// DeleteUser api for deleting a user
2016-03-13 18:49:16 -04:00
func DeleteUser ( ctx * context . APIContext ) {
2017-11-12 23:02:25 -08:00
// swagger:operation DELETE /admin/users/{username} admin adminDeleteUser
// ---
// summary: Delete a user
// produces:
// - application/json
// parameters:
// - name: username
// in: path
2025-06-30 06:17:45 +02:00
// description: username of the user to delete
2017-11-12 23:02:25 -08:00
// type: string
// required: true
2023-03-13 14:41:38 -05:00
// - name: purge
// in: query
// description: purge the user from the system completely
// type: boolean
2017-11-12 23:02:25 -08:00
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
2023-07-24 16:48:44 +08:00
// "404":
// "$ref": "#/responses/notFound"
2017-11-12 23:02:25 -08:00
// "422":
// "$ref": "#/responses/validationError"
2019-12-20 18:07:12 +01:00
2022-03-26 10:04:22 +01:00
if ctx . ContextUser . IsOrganization ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Errorf ( "%s is an organization not a user" , ctx . ContextUser . Name ) )
2020-02-03 17:46:33 +01:00
return
}
2022-05-09 04:22:55 +08:00
// admin should not delete themself
if ctx . ContextUser . ID == ctx . Doer . ID {
2025-04-01 12:14:01 +02:00
ctx . APIError ( http . StatusUnprocessableEntity , errors . New ( "you cannot delete yourself" ) )
2022-05-09 04:22:55 +08:00
return
}
2022-07-14 08:22:09 +01:00
if err := user_service . DeleteUser ( ctx , ctx . ContextUser , ctx . FormBool ( "purge" ) ) ; err != nil {
2024-12-20 10:05:29 -08:00
if repo_model . IsErrUserOwnRepos ( err ) ||
org_model . IsErrUserHasOrgs ( err ) ||
packages_model . IsErrUserOwnPackages ( err ) ||
user_model . IsErrDeleteLastAdminUser ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , err )
2015-12-05 17:13:13 -05:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2015-12-05 17:13:13 -05:00
}
return
}
2022-03-26 10:04:22 +01:00
log . Trace ( "Account deleted by admin(%s): %s" , ctx . Doer . Name , ctx . ContextUser . Name )
2015-12-05 17:13:13 -05:00
2019-12-20 18:07:12 +01:00
ctx . Status ( http . StatusNoContent )
2015-12-05 17:13:13 -05:00
}
2016-11-24 15:04:31 +08:00
// CreatePublicKey api for creating a public key to a user
2021-01-26 23:36:53 +08:00
func CreatePublicKey ( ctx * context . APIContext ) {
2017-11-12 23:02:25 -08:00
// swagger:operation POST /admin/users/{username}/keys admin adminCreatePublicKey
// ---
// summary: Add a public key on behalf of a user
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: username
// in: path
2025-06-30 06:17:45 +02:00
// description: username of the user who is to receive a public key
2017-11-12 23:02:25 -08:00
// type: string
// required: true
2018-10-21 04:40:42 +01:00
// - name: key
// in: body
// schema:
// "$ref": "#/definitions/CreateKeyOption"
2017-11-12 23:02:25 -08:00
// responses:
// "201":
// "$ref": "#/responses/PublicKey"
// "403":
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
2022-03-26 10:04:22 +01:00
2021-01-26 23:36:53 +08:00
form := web . GetForm ( ctx ) . ( * api . CreateKeyOption )
2022-03-26 10:04:22 +01:00
user . CreateUserPublicKey ( ctx , * form , ctx . ContextUser . ID )
2015-12-05 17:13:13 -05:00
}
2017-12-06 12:27:10 +02:00
// DeleteUserPublicKey api for deleting a user's public key
func DeleteUserPublicKey ( ctx * context . APIContext ) {
// swagger:operation DELETE /admin/users/{username}/keys/{id} admin adminDeleteUserPublicKey
// ---
// summary: Delete a user's public key
// produces:
// - application/json
// parameters:
// - name: username
// in: path
2025-06-30 06:17:45 +02:00
// description: username of the user whose public key is to be deleted
2017-12-06 12:27:10 +02:00
// type: string
// required: true
// - name: id
// in: path
// description: id of the key to delete
// type: integer
2018-10-21 04:40:42 +01:00
// format: int64
2017-12-06 12:27:10 +02:00
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
// "404":
// "$ref": "#/responses/notFound"
2019-12-20 18:07:12 +01:00
2024-12-24 21:47:45 +08:00
if err := asymkey_service . DeletePublicKey ( ctx , ctx . ContextUser , ctx . PathParamInt64 ( "id" ) ) ; err != nil {
2021-12-10 16:14:24 +08:00
if asymkey_model . IsErrKeyNotExist ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIErrorNotFound ( )
2021-12-10 16:14:24 +08:00
} else if asymkey_model . IsErrKeyAccessDenied ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusForbidden , "You do not have access to this key" )
2017-12-06 12:27:10 +02:00
} else {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2017-12-06 12:27:10 +02:00
}
return
}
2022-03-26 10:04:22 +01:00
log . Trace ( "Key deleted by admin(%s): %s" , ctx . Doer . Name , ctx . ContextUser . Name )
2017-12-06 12:27:10 +02:00
2019-12-20 18:07:12 +01:00
ctx . Status ( http . StatusNoContent )
2017-12-06 12:27:10 +02:00
}
2019-01-24 04:00:19 +05:30
2023-03-15 19:53:01 +08:00
// SearchUsers API for getting information of the users according the filter conditions
func SearchUsers ( ctx * context . APIContext ) {
// swagger:operation GET /admin/users admin adminSearchUsers
2019-01-24 04:00:19 +05:30
// ---
2023-03-15 19:53:01 +08:00
// summary: Search users according filter conditions
2019-01-24 04:00:19 +05:30
// produces:
// - application/json
2020-01-24 19:00:29 +00:00
// parameters:
2023-03-15 19:53:01 +08:00
// - name: source_id
// in: query
// description: ID of the user's login source to search for
// type: integer
// format: int64
// - name: login_name
// in: query
2025-06-30 06:17:45 +02:00
// description: identifier of the user, provided by the external authenticator
2023-03-15 19:53:01 +08:00
// type: string
2020-01-24 19:00:29 +00:00
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
2020-06-09 06:57:38 +02:00
// description: page size of results
2020-01-24 19:00:29 +00:00
// type: integer
2025-12-11 23:12:06 -05:00
// - name: sort
// in: query
// description: sort users by attribute. Supported values are
// "name", "created", "updated" and "id".
// Default is "name"
// type: string
// - name: order
// in: query
// description: sort order, either "asc" (ascending) or "desc" (descending).
// Default is "asc", ignored if "sort" is not specified.
// type: string
// - name: q
// in: query
// description: search term (username, full name, email)
// type: string
// - name: visibility
// in: query
// description: visibility filter. Supported values are
// "public", "limited" and "private".
// type: string
// - name: is_active
// in: query
// description: filter active users
// type: boolean
// - name: is_admin
// in: query
// description: filter admin users
// type: boolean
// - name: is_restricted
// in: query
// description: filter restricted users
// type: boolean
// - name: is_2fa_enabled
// in: query
// description: filter 2FA enabled users
// type: boolean
// - name: is_prohibit_login
// in: query
// description: filter login prohibited users
// type: boolean
2019-01-24 04:00:19 +05:30
// responses:
// "200":
// "$ref": "#/responses/UserList"
// "403":
// "$ref": "#/responses/forbidden"
2025-12-11 23:12:06 -05:00
// "422":
// "$ref": "#/responses/validationError"
2019-12-20 18:07:12 +01:00
2020-06-21 10:22:06 +02:00
listOptions := utils . GetListOptions ( ctx )
2025-12-11 23:12:06 -05:00
orderBy := db . SearchOrderByAlphabetically
sortMode := ctx . FormString ( "sort" )
if len ( sortMode ) > 0 {
sortOrder := ctx . FormString ( "order" )
if len ( sortOrder ) == 0 {
sortOrder = "asc"
}
if searchModeMap , ok := user_model . AdminUserOrderByMap [ sortOrder ] ; ok {
if order , ok := searchModeMap [ sortMode ] ; ok {
orderBy = order
} else {
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Errorf ( "Invalid sort mode: \"%s\"" , sortMode ) )
return
}
} else {
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Errorf ( "Invalid sort order: \"%s\"" , sortOrder ) )
return
}
}
var visible [ ] api . VisibleType
visibilityParam := ctx . FormString ( "visibility" )
if len ( visibilityParam ) > 0 {
if visibility , ok := api . VisibilityModes [ visibilityParam ] ; ok {
visible = [ ] api . VisibleType { visibility }
} else {
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Errorf ( "Invalid visibility: \"%s\"" , visibilityParam ) )
return
}
}
searchOpts := user_model . SearchUserOptions {
Actor : ctx . Doer ,
Types : [ ] user_model . UserType { user_model . UserTypeIndividual } ,
LoginName : ctx . FormTrim ( "login_name" ) ,
SourceID : ctx . FormInt64 ( "source_id" ) ,
Keyword : ctx . FormTrim ( "q" ) ,
Visible : visible ,
OrderBy : orderBy ,
ListOptions : listOptions ,
SearchByEmail : true ,
}
if ctx . FormString ( "is_active" ) != "" {
searchOpts . IsActive = optional . Some ( ctx . FormBool ( "is_active" ) )
}
if ctx . FormString ( "is_admin" ) != "" {
searchOpts . IsAdmin = optional . Some ( ctx . FormBool ( "is_admin" ) )
}
if ctx . FormString ( "is_restricted" ) != "" {
searchOpts . IsRestricted = optional . Some ( ctx . FormBool ( "is_restricted" ) )
}
if ctx . FormString ( "is_2fa_enabled" ) != "" {
searchOpts . IsTwoFactorEnabled = optional . Some ( ctx . FormBool ( "is_2fa_enabled" ) )
}
if ctx . FormString ( "is_prohibit_login" ) != "" {
searchOpts . IsProhibitLogin = optional . Some ( ctx . FormBool ( "is_prohibit_login" ) )
}
users , maxResults , err := user_model . SearchUsers ( ctx , searchOpts )
2019-01-24 04:00:19 +05:30
if err != nil {
2025-02-18 04:41:03 +08:00
ctx . APIErrorInternal ( err )
2019-01-24 04:00:19 +05:30
return
}
2019-04-15 17:36:59 +01:00
results := make ( [ ] * api . User , len ( users ) )
for i := range users {
2023-02-15 21:37:34 +08:00
results [ i ] = convert . ToUser ( ctx , users [ i ] , ctx . Doer )
2019-04-15 17:36:59 +01:00
}
2026-03-08 15:35:50 +01:00
ctx . SetLinkHeader ( maxResults , listOptions . PageSize )
2021-08-12 14:43:08 +02:00
ctx . SetTotalCountHeader ( maxResults )
2019-12-20 18:07:12 +01:00
ctx . JSON ( http . StatusOK , & results )
2019-01-24 04:00:19 +05:30
}
2023-03-14 03:45:21 -04:00
// RenameUser api for renaming a user
func RenameUser ( ctx * context . APIContext ) {
// swagger:operation POST /admin/users/{username}/rename admin adminRenameUser
// ---
// summary: Rename a user
// produces:
// - application/json
// parameters:
// - name: username
// in: path
2025-06-30 06:17:45 +02:00
// description: current username of the user
2023-03-14 03:45:21 -04:00
// type: string
// required: true
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/RenameUserOption"
// responses:
// "204":
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
// "422":
// "$ref": "#/responses/validationError"
if ctx . ContextUser . IsOrganization ( ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , fmt . Errorf ( "%s is an organization not a user" , ctx . ContextUser . Name ) )
2023-03-14 03:45:21 -04:00
return
}
newName := web . GetForm ( ctx ) . ( * api . RenameUserOption ) . NewName
2025-01-31 21:59:49 -03:00
// Check if username has been changed
2025-11-23 13:59:55 -07:00
if err := user_service . RenameUser ( ctx , ctx . ContextUser , newName , ctx . Doer ) ; err != nil {
2025-01-31 21:59:49 -03:00
if user_model . IsErrUserAlreadyExist ( err ) || db . IsErrNameReserved ( err ) || db . IsErrNamePatternNotAllowed ( err ) || db . IsErrNameCharsNotAllowed ( err ) {
2025-02-17 14:13:17 +08:00
ctx . APIError ( http . StatusUnprocessableEntity , err )
2025-01-31 21:59:49 -03:00
} else {
2025-02-17 14:13:17 +08:00
ctx . APIErrorInternal ( err )
2023-03-14 03:45:21 -04:00
}
return
}
2024-02-04 14:29:09 +01:00
ctx . Status ( http . StatusNoContent )
2023-03-14 03:45:21 -04:00
}