Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add user rename endpoint to admin api #22789

Merged
merged 27 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
363a51e
add user rename endpoint to admin api
techknowlogick Feb 6, 2023
9d010ef
Merge branch 'main' into rename-user-endpoint
techknowlogick Feb 20, 2023
6e37106
update swagger
techknowlogick Feb 21, 2023
b960b1f
fix swagger
techknowlogick Mar 2, 2023
87ccd60
fix swagger
techknowlogick Mar 2, 2023
ebe6a71
remove log debugging
techknowlogick Mar 2, 2023
e4b035f
Merge branch 'main' into rename-user-endpoint
techknowlogick Mar 9, 2023
83ac9e5
error will never be reached
techknowlogick Mar 9, 2023
d44c8e0
update swagger docs
techknowlogick Mar 9, 2023
5dd3a5f
move renameUser to service
techknowlogick Mar 9, 2023
cb84b4e
make fmt
techknowlogick Mar 9, 2023
2a1a46f
add newline to end of swagger template
techknowlogick Mar 9, 2023
df46a9f
move db into tx
techknowlogick Mar 9, 2023
e6437df
noop for no user change
techknowlogick Mar 9, 2023
8c71935
adds ctx back
techknowlogick Mar 9, 2023
07cc2ef
make lint
techknowlogick Mar 9, 2023
09d410e
add context
techknowlogick Mar 13, 2023
0d7542b
add context and move rename to service
techknowlogick Mar 13, 2023
599b318
Merge branch 'main' into rename-user-endpoint
techknowlogick Mar 13, 2023
621cd19
fix panic
techknowlogick Mar 13, 2023
e37edbd
Merge branch 'rename-user-endpoint' of github.com:techknowlogick/gite…
techknowlogick Mar 13, 2023
d53ea52
fix panic
techknowlogick Mar 13, 2023
5e9192b
unwrap error
techknowlogick Mar 13, 2023
f30a88d
remove duped code
techknowlogick Mar 14, 2023
9fbb7d8
Merge branch 'main' into rename-user-endpoint
techknowlogick Mar 14, 2023
259dbeb
Merge branch 'main' into rename-user-endpoint
techknowlogick Mar 14, 2023
79ed00f
Apply suggestions from code review
techknowlogick Mar 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions modules/structs/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,3 +93,12 @@ type UserSettingsOptions struct {
HideEmail *bool `json:"hide_email"`
HideActivity *bool `json:"hide_activity"`
}

// RenameUserOption options when renaming a user
type RenameUserOption struct {
// New username for this user. This name cannot be in use yet by any other user.
//
// required: true
// unique: true
NewName string `json:"new_username" binding:"Required"`
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved
}
58 changes: 58 additions & 0 deletions routers/api/v1/admin/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -457,3 +457,61 @@ func GetAllUsers(ctx *context.APIContext) {
ctx.SetTotalCountHeader(maxResults)
ctx.JSON(http.StatusOK, &results)
}

// 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
// description: existing username of user
// 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() {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("%s is an organization not a user", ctx.ContextUser.Name))
return
}

newName := web.GetForm(ctx).(*api.RenameUserOption).NewName
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved

if strings.EqualFold(newName, ctx.ContextUser.Name) {
// Noop as username is not changed
ctx.Status(http.StatusNoContent)
return
}

// Check if user name has been changed
if err := user_service.RenameUser(ctx, ctx.ContextUser, newName); err != nil {
switch {
case user_model.IsErrUserAlreadyExist(err):
ctx.Error(http.StatusUnprocessableEntity, "", ctx.Tr("form.username_been_taken"))
case db.IsErrNameReserved(err):
ctx.Error(http.StatusUnprocessableEntity, "", ctx.Tr("user.form.name_reserved", newName))
case db.IsErrNamePatternNotAllowed(err):
ctx.Error(http.StatusUnprocessableEntity, "", ctx.Tr("user.form.name_pattern_not_allowed", newName))
case db.IsErrNameCharsNotAllowed(err):
ctx.Error(http.StatusUnprocessableEntity, "", ctx.Tr("user.form.name_chars_not_allowed", newName))
default:
ctx.ServerError("ChangeUserName", err)
}
return
}
ctx.Status(http.StatusNoContent)
}
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,7 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/orgs", org.ListUserOrgs)
m.Post("/orgs", bind(api.CreateOrgOption{}), admin.CreateOrg)
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
m.Post("/rename", bind(api.RenameUserOption{}), admin.RenameUser)
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved
}, context_service.UserAssignmentAPI())
})
m.Group("/unadopted", func() {
Expand Down
3 changes: 3 additions & 0 deletions routers/api/v1/swagger/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ type swaggerParameterBodies struct {
// in:body
CreateKeyOption api.CreateKeyOption

// in:body
RenameUserOption api.RenameUserOption

// in:body
CreateLabelOption api.CreateLabelOption
// in:body
Expand Down
46 changes: 46 additions & 0 deletions services/user/rename.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package user

import (
"context"
"fmt"
"strings"

user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/services/agit"
container_service "code.gitea.io/gitea/services/packages/container"
)

func renameUser(ctx context.Context, u *user_model.User, newUserName string) (err error) {
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved
if u.IsOrganization() {
return fmt.Errorf("cannot rename organization")
}

if u.LowerName == strings.ToLower(newUserName) {
return fmt.Errorf("new username is the same as the old one")
}

if err := user_model.ChangeUserName(u, newUserName); err != nil {
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved
return err
}

err = agit.UserNameChanged(u, newUserName)
if err != nil {
return err
}
if err = container_service.UpdateRepositoryNames(ctx, u, newUserName); err != nil {
return err
}

u.Name = newUserName
u.LowerName = strings.ToLower(newUserName)
if err := user_model.UpdateUser(ctx, u, false); err != nil {
return err
}

log.Trace("User name changed: %s -> %s", u.Name, newUserName)
return nil
}
16 changes: 16 additions & 0 deletions services/user/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,22 @@ import (
"code.gitea.io/gitea/services/packages"
)

// RenameUser renames a user
func RenameUser(ctx context.Context, u *user_model.User, newUserName string) error {
techknowlogick marked this conversation as resolved.
Show resolved Hide resolved
ctx, committer, err := db.TxContext(ctx)
if err != nil {
return err
}
defer committer.Close()
if err := renameUser(ctx, u, newUserName); err != nil {
return fmt.Errorf("renameUser: %w", err)
}
if err := committer.Commit(); err != nil {
return err
}
return err
}

// DeleteUser completely and permanently deletes everything of a user,
// but issues/comments/pulls will be kept and shown as someone has been deleted,
// unless the user is younger than USER_DELETE_WITH_COMMENTS_MAX_DAYS.
Expand Down
56 changes: 56 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,46 @@
}
}
},
"/admin/users/{username}/rename": {
"post": {
"produces": [
"application/json"
],
"tags": [
"admin"
],
"summary": "Rename a user",
"operationId": "adminRenameUser",
"parameters": [
{
"type": "string",
"description": "existing username of user",
"name": "username",
"in": "path",
"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"
}
}
}
},
"/admin/users/{username}/repos": {
"post": {
"consumes": [
Expand Down Expand Up @@ -18943,6 +18983,22 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"RenameUserOption": {
"description": "RenameUserOption options when renaming a user",
"type": "object",
"required": [
"new_username"
],
"properties": {
"new_username": {
"description": "New username for this user. This name cannot be in use yet by any other user.",
"type": "string",
"uniqueItems": true,
"x-go-name": "NewName"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"RepoCollaboratorPermission": {
"description": "RepoCollaboratorPermission to get repository permission for a collaborator",
"type": "object",
Expand Down