forked from Gitlink/gitea_hat
新增:更新用户接口
This commit is contained in:
parent
34f7949c09
commit
7cadb49770
|
@ -0,0 +1,10 @@
|
|||
package structs
|
||||
|
||||
import (
|
||||
gitea_api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
type HatEditUserOption struct {
|
||||
NewName string `json:"new_name" binding:"MaxSize(40)"`
|
||||
*gitea_api.EditUserOption
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
package admin
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/password"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/agit"
|
||||
container_service "code.gitea.io/gitea/services/packages/container"
|
||||
hat_api "code.gitlink.org.cn/Gitlink/gitea_hat.git/modules/structs"
|
||||
)
|
||||
|
||||
func parseAuthSource(ctx *context.APIContext, u *user_model.User, sourceID int64, loginName string) {
|
||||
if sourceID == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
source, err := auth.GetSourceByID(sourceID)
|
||||
if err != nil {
|
||||
if auth.IsErrSourceNotExist(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "auth.GetSourceByID", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
u.LoginType = source.Type
|
||||
u.LoginSource = source.ID
|
||||
u.LoginName = loginName
|
||||
}
|
||||
|
||||
func EditUser(ctx *context.APIContext) {
|
||||
form := web.GetForm(ctx).(*hat_api.HatEditUserOption)
|
||||
parseAuthSource(ctx, ctx.ContextUser, form.SourceID, form.LoginName)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
if len(form.Password) != 0 {
|
||||
if len(form.Password) < setting.MinPasswordLength {
|
||||
ctx.Error(http.StatusBadRequest, "PasswordTooShort", fmt.Errorf("password must be at least %d characters", setting.MinPasswordLength))
|
||||
return
|
||||
}
|
||||
if !password.IsComplexEnough(form.Password) {
|
||||
err := errors.New("PasswordComplexity")
|
||||
ctx.Error(http.StatusBadRequest, "PasswordComplexity", err)
|
||||
return
|
||||
}
|
||||
pwned, err := password.IsPwned(ctx, form.Password)
|
||||
if pwned {
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
}
|
||||
ctx.Data["Err_Password"] = true
|
||||
ctx.Error(http.StatusBadRequest, "PasswordPwned", errors.New("PasswordPwned"))
|
||||
return
|
||||
}
|
||||
if ctx.ContextUser.Salt, err = user_model.GetUserSalt(); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
||||
return
|
||||
}
|
||||
if err = ctx.ContextUser.SetPassword(form.Password); err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if form.MustChangePassword != nil {
|
||||
ctx.ContextUser.MustChangePassword = *form.MustChangePassword
|
||||
}
|
||||
|
||||
if len(form.NewName) != 0 && ctx.ContextUser.Name != form.NewName {
|
||||
if err := handleUsernameChange(ctx, ctx.ContextUser, form.NewName); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
||||
return
|
||||
}
|
||||
ctx.ContextUser.Name = form.NewName
|
||||
ctx.ContextUser.LowerName = strings.ToLower(form.NewName)
|
||||
}
|
||||
|
||||
ctx.ContextUser.LoginName = form.LoginName
|
||||
|
||||
if form.FullName != nil {
|
||||
ctx.ContextUser.FullName = *form.FullName
|
||||
}
|
||||
var emailChanged bool
|
||||
if form.Email != nil {
|
||||
email := strings.TrimSpace(*form.Email)
|
||||
if len(email) == 0 {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Errorf("email is not allowed to be empty string"))
|
||||
return
|
||||
}
|
||||
|
||||
if err := user_model.ValidateEmail(email); err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
emailChanged = !strings.EqualFold(ctx.ContextUser.Email, email)
|
||||
ctx.ContextUser.Email = email
|
||||
}
|
||||
if form.Website != nil {
|
||||
ctx.ContextUser.Website = *form.Website
|
||||
}
|
||||
if form.Location != nil {
|
||||
ctx.ContextUser.Location = *form.Location
|
||||
}
|
||||
if form.Description != nil {
|
||||
ctx.ContextUser.Description = *form.Description
|
||||
}
|
||||
if form.Active != nil {
|
||||
ctx.ContextUser.IsActive = *form.Active
|
||||
}
|
||||
if len(form.Visibility) != 0 {
|
||||
ctx.ContextUser.Visibility = api.VisibilityModes[form.Visibility]
|
||||
}
|
||||
if form.Admin != nil {
|
||||
ctx.ContextUser.IsAdmin = *form.Admin
|
||||
}
|
||||
if form.AllowGitHook != nil {
|
||||
ctx.ContextUser.AllowGitHook = *form.AllowGitHook
|
||||
}
|
||||
if form.AllowImportLocal != nil {
|
||||
ctx.ContextUser.AllowImportLocal = *form.AllowImportLocal
|
||||
}
|
||||
if form.MaxRepoCreation != nil {
|
||||
ctx.ContextUser.MaxRepoCreation = *form.MaxRepoCreation
|
||||
}
|
||||
if form.AllowCreateOrganization != nil {
|
||||
ctx.ContextUser.AllowCreateOrganization = *form.AllowCreateOrganization
|
||||
}
|
||||
if form.ProhibitLogin != nil {
|
||||
ctx.ContextUser.ProhibitLogin = *form.ProhibitLogin
|
||||
}
|
||||
if form.Restricted != nil {
|
||||
ctx.ContextUser.IsRestricted = *form.Restricted
|
||||
}
|
||||
|
||||
if err := user_model.UpdateUser(ctx, ctx.ContextUser, emailChanged); err != nil {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) ||
|
||||
user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
log.Trace("Account profile updated by admin (%s): %s", ctx.Doer.Name, ctx.ContextUser.Name)
|
||||
|
||||
ctx.JSON(http.StatusOK, convert.ToUser(ctx.ContextUser, ctx.Doer))
|
||||
}
|
||||
|
||||
func handleUsernameChange(ctx *context.APIContext, user *user_model.User, newName string) error {
|
||||
// Non-local users are not allowed to change their username.
|
||||
if !user.IsLocal() {
|
||||
ctx.Flash.Error(ctx.Tr("form.username_change_not_local_user"))
|
||||
return fmt.Errorf(ctx.Tr("form.username_change_not_local_user"))
|
||||
}
|
||||
|
||||
// Check if user name has been changed
|
||||
if user.LowerName != strings.ToLower(newName) {
|
||||
if err := user_model.ChangeUserName(user, newName); err != nil {
|
||||
switch {
|
||||
case user_model.IsErrUserAlreadyExist(err):
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", ctx.Tr("form.username_been_taken"))
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", ctx.Tr("form.email_been_used"))
|
||||
case db.IsErrNameReserved(err):
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", ctx.Tr("user.form.name_reserved", newName))
|
||||
case db.IsErrNamePatternNotAllowed(err):
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", ctx.Tr("user.form.name_pattern_not_allowed", newName))
|
||||
case db.IsErrNameCharsNotAllowed(err):
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", ctx.Tr("user.form.name_chars_not_allowed", newName))
|
||||
default:
|
||||
ctx.Error(http.StatusInternalServerError, "ChangeUserName", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := repo_model.UpdateRepositoryOwnerNames(user.ID, newName); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateRepository", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// update all agit flow pull request header
|
||||
err := agit.UserNameChanged(user, newName)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "agit.UserNameChanged", err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := container_service.UpdateRepositoryNames(ctx, user, newName); err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryNames", err)
|
||||
return err
|
||||
}
|
||||
|
||||
log.Trace("User name changed: %s -> %s", user.Name, newName)
|
||||
return nil
|
||||
}
|
|
@ -24,6 +24,7 @@ import (
|
|||
"code.gitea.io/gitea/routers/api/v1/misc"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
context_service "code.gitea.io/gitea/services/context"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/admin"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/org"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/repo"
|
||||
"code.gitlink.org.cn/Gitlink/gitea_hat.git/routers/hat/user"
|
||||
|
@ -127,6 +128,14 @@ func Routers(ctx gocontext.Context) *web.Route {
|
|||
m.Group("/orgs/{org}", func() {
|
||||
m.Combo("").Patch(reqToken(), reqOrgOwnership(), bind(hat_api.EditOrgOption{}), org.Edit)
|
||||
}, orgAssignment(true))
|
||||
|
||||
m.Group("/admin", func() {
|
||||
m.Group("/users", func() {
|
||||
m.Group("/{username}", func() {
|
||||
m.Combo("").Patch(bind(hat_api.HatEditUserOption{}), admin.EditUser)
|
||||
}, context_service.UserAssignmentAPI())
|
||||
})
|
||||
}, reqToken(), reqSiteAdmin())
|
||||
})
|
||||
|
||||
return m
|
||||
|
@ -379,3 +388,13 @@ func reqToken() func(ctx *context.APIContext) {
|
|||
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
|
||||
}
|
||||
}
|
||||
|
||||
// reqSiteAdmin user should be the site admin
|
||||
func reqSiteAdmin() func(ctx *context.APIContext) {
|
||||
return func(ctx *context.APIContext) {
|
||||
if !ctx.IsUserSiteAdmin() {
|
||||
ctx.Error(http.StatusForbidden, "reqSiteAdmin", "user should be the site admin")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue