Merge branch 'feat/1.1.2/user' into test
This commit is contained in:
@@ -251,6 +251,10 @@ backend:
|
||||
other: Access denied
|
||||
page_access_denied:
|
||||
other: You do not have access to this page.
|
||||
add_bulk_users_format_error:
|
||||
other: "Error {{.Field}} format near '{{.Content}}' at line {{.Line}}. {{.ExtraMessage}}"
|
||||
add_bulk_users_amount_error:
|
||||
other: "The number of users you add at once should be in the range of 1-{{.MaxAmount}}."
|
||||
config:
|
||||
read_config_failed:
|
||||
other: Read config failed
|
||||
|
||||
@@ -2,6 +2,7 @@ package constant
|
||||
|
||||
const (
|
||||
DefaultPageSize = 20 // Default number of pages
|
||||
DefaultBulkUser = 5000
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -76,6 +76,9 @@ const (
|
||||
AdminCannotModifySelfStatus = "error.admin.cannot_modify_self_status"
|
||||
UserAccessDenied = "error.user.access_denied"
|
||||
UserPageAccessDenied = "error.user.page_access_denied"
|
||||
|
||||
AddBulkUsersFormatError = "error.user.add_bulk_users_format_error"
|
||||
AddBulkUsersAmountError = "error.user.add_bulk_users_amount_error"
|
||||
)
|
||||
|
||||
// user external login reasons
|
||||
|
||||
@@ -91,6 +91,26 @@ func (uc *UserAdminController) AddUser(ctx *gin.Context) {
|
||||
handler.HandleResponse(ctx, err, nil)
|
||||
}
|
||||
|
||||
// AddUsers add users
|
||||
// @Summary add users
|
||||
// @Description add users
|
||||
// @Security ApiKeyAuth
|
||||
// @Tags admin
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param data body schema.AddUserReq true "user"
|
||||
// @Success 200 {object} handler.RespBody
|
||||
// @Router /answer/admin/api/users [post]
|
||||
func (uc *UserAdminController) AddUsers(ctx *gin.Context) {
|
||||
req := &schema.AddUsersReq{}
|
||||
if handler.BindAndCheck(ctx, req) {
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := uc.userService.AddUsers(ctx, req)
|
||||
handler.HandleResponse(ctx, err, resp)
|
||||
}
|
||||
|
||||
// UpdateUserPassword update user password
|
||||
// @Summary update user password
|
||||
// @Description update user password
|
||||
|
||||
@@ -70,6 +70,15 @@ func (ur *userAdminRepo) AddUser(ctx context.Context, user *entity.User) (err er
|
||||
return
|
||||
}
|
||||
|
||||
// AddUsers add users
|
||||
func (ur *userAdminRepo) AddUsers(ctx context.Context, users []*entity.User) (err error) {
|
||||
_, err = ur.data.DB.Context(ctx).Insert(users)
|
||||
if err != nil {
|
||||
err = errors.InternalServer(reason.DatabaseError).WithError(err).WithStack()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// UpdateUserPassword update user password
|
||||
func (ur *userAdminRepo) UpdateUserPassword(ctx context.Context, userID string, password string) (err error) {
|
||||
_, err = ur.data.DB.Context(ctx).ID(userID).Update(&entity.User{Pass: password})
|
||||
|
||||
@@ -261,6 +261,7 @@ func (a *AnswerAPIRouter) RegisterAnswerAdminAPIRouter(r *gin.RouterGroup) {
|
||||
r.GET("/user/activation", a.adminUserController.GetUserActivation)
|
||||
r.POST("/user/activation", a.adminUserController.SendUserActivation)
|
||||
r.POST("/user", a.adminUserController.AddUser)
|
||||
r.POST("/users", a.adminUserController.AddUsers)
|
||||
r.PUT("/user/password", a.adminUserController.UpdateUserPassword)
|
||||
|
||||
// reason
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
package schema
|
||||
|
||||
import "github.com/answerdev/answer/internal/base/constant"
|
||||
import (
|
||||
"context"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/reason"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/base/validator"
|
||||
"github.com/segmentfault/pacman/errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// UpdateUserStatusReq update user request
|
||||
type UpdateUserStatusReq struct {
|
||||
@@ -87,6 +96,69 @@ type AddUserReq struct {
|
||||
LoginUserID string `json:"-"`
|
||||
}
|
||||
|
||||
// AddUsersReq add users request
|
||||
type AddUsersReq struct {
|
||||
// users info line by line
|
||||
UsersStr string `json:"users"`
|
||||
Users []*AddUserReq `json:"-"`
|
||||
}
|
||||
|
||||
type AddUsersErrorData struct {
|
||||
// optional. error field name.
|
||||
Field string `json:"field"`
|
||||
// must. error line number.
|
||||
Line int `json:"line"`
|
||||
// must. error content.
|
||||
Content string `json:"content"`
|
||||
// optional. error message.
|
||||
ExtraMessage string `json:"extra_message"`
|
||||
}
|
||||
|
||||
func (e *AddUsersErrorData) SetErrField(errFields []*validator.FormErrorField) {
|
||||
if len(errFields) > 0 {
|
||||
e.Field = errFields[0].ErrorField
|
||||
e.ExtraMessage = errFields[0].ErrorMsg
|
||||
}
|
||||
}
|
||||
|
||||
func (req *AddUsersReq) ParseUsers(ctx context.Context) (errFields []*validator.FormErrorField, err error) {
|
||||
req.UsersStr = strings.TrimSpace(req.UsersStr)
|
||||
lines := strings.Split(req.UsersStr, "\n")
|
||||
req.Users = make([]*AddUserReq, 0)
|
||||
for i, line := range lines {
|
||||
arr := strings.Split(line, ",")
|
||||
if len(arr) != 3 {
|
||||
errFields = append([]*validator.FormErrorField{}, &validator.FormErrorField{
|
||||
ErrorField: "users",
|
||||
ErrorMsg: translator.TrWithData(handler.GetLangByCtx(ctx), reason.AddBulkUsersFormatError,
|
||||
&AddUsersErrorData{
|
||||
Line: i + 1,
|
||||
Content: line,
|
||||
}),
|
||||
})
|
||||
return errFields, errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
req.Users = append(req.Users, &AddUserReq{
|
||||
DisplayName: strings.TrimSpace(arr[0]),
|
||||
Email: strings.TrimSpace(arr[1]),
|
||||
Password: strings.TrimSpace(arr[2]),
|
||||
})
|
||||
}
|
||||
|
||||
// check users amount
|
||||
if len(req.Users) <= 0 || len(req.Users) > constant.DefaultBulkUser {
|
||||
errFields = append([]*validator.FormErrorField{}, &validator.FormErrorField{
|
||||
ErrorField: "users",
|
||||
ErrorMsg: translator.TrWithData(handler.GetLangByCtx(ctx), reason.AddBulkUsersAmountError,
|
||||
map[string]int{
|
||||
"MaxAmount": constant.DefaultBulkUser,
|
||||
}),
|
||||
})
|
||||
return errFields, errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// UpdateUserPasswordReq update user password request
|
||||
type UpdateUserPasswordReq struct {
|
||||
UserID string `validate:"required" json:"user_id"`
|
||||
|
||||
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/answerdev/answer/internal/base/constant"
|
||||
"github.com/answerdev/answer/internal/base/handler"
|
||||
"github.com/answerdev/answer/internal/base/translator"
|
||||
"github.com/answerdev/answer/internal/base/validator"
|
||||
"github.com/answerdev/answer/internal/service/export"
|
||||
"github.com/google/uuid"
|
||||
"net/mail"
|
||||
@@ -34,6 +37,7 @@ type UserAdminRepo interface {
|
||||
GetUserPage(ctx context.Context, page, pageSize int, user *entity.User,
|
||||
usernameOrDisplayName string, isStaff bool) (users []*entity.User, total int64, err error)
|
||||
AddUser(ctx context.Context, user *entity.User) (err error)
|
||||
AddUsers(ctx context.Context, users []*entity.User) (err error)
|
||||
UpdateUserPassword(ctx context.Context, userID string, password string) (err error)
|
||||
}
|
||||
|
||||
@@ -165,6 +169,76 @@ func (us *UserAdminService) AddUser(ctx context.Context, req *schema.AddUserReq)
|
||||
return
|
||||
}
|
||||
|
||||
// AddUsers add users
|
||||
func (us *UserAdminService) AddUsers(ctx context.Context, req *schema.AddUsersReq) (
|
||||
resp []*validator.FormErrorField, err error) {
|
||||
resp, err = req.ParseUsers(ctx)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
|
||||
users, resp, err := us.formatBulkAddUsers(ctx, req)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
err = us.userRepo.AddUsers(ctx, users)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (us *UserAdminService) formatBulkAddUsers(ctx context.Context, req *schema.AddUsersReq) (
|
||||
users []*entity.User, errFields []*validator.FormErrorField, err error) {
|
||||
lang := handler.GetLangByCtx(ctx)
|
||||
val := validator.GetValidatorByLang(lang)
|
||||
errorData := &schema.AddUsersErrorData{Line: -1}
|
||||
for line, user := range req.Users {
|
||||
if fields, e := val.Check(user); e != nil {
|
||||
errorData.SetErrField(fields)
|
||||
errorData.Line = line + 1
|
||||
errorData.Content = fmt.Sprintf("%s, %s", user.DisplayName, user.Email)
|
||||
break
|
||||
}
|
||||
|
||||
_, has, e := us.userRepo.GetUserInfoByEmail(ctx, user.Email)
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
if has {
|
||||
errorData.Field = "email"
|
||||
errorData.Line = line + 1
|
||||
errorData.Content = user.Email
|
||||
errorData.ExtraMessage = translator.Tr(lang, reason.EmailDuplicate)
|
||||
break
|
||||
}
|
||||
|
||||
userInfo := &entity.User{}
|
||||
userInfo.EMail = user.Email
|
||||
userInfo.DisplayName = user.DisplayName
|
||||
hashPwd, _ := bcrypt.GenerateFromPassword([]byte(user.Password), bcrypt.DefaultCost)
|
||||
userInfo.Pass = string(hashPwd)
|
||||
userInfo.Username, err = us.userCommonService.MakeUsername(ctx, userInfo.DisplayName)
|
||||
if err != nil {
|
||||
errorData.Field = "display_name"
|
||||
errorData.Line = line + 1
|
||||
errorData.Content = user.DisplayName
|
||||
errorData.ExtraMessage = translator.Tr(lang, reason.UsernameInvalid)
|
||||
break
|
||||
}
|
||||
userInfo.MailStatus = entity.EmailStatusAvailable
|
||||
userInfo.Status = entity.UserStatusAvailable
|
||||
userInfo.Rank = 1
|
||||
users = append(users, userInfo)
|
||||
}
|
||||
|
||||
if errorData.Line != -1 {
|
||||
errFields = append([]*validator.FormErrorField{}, &validator.FormErrorField{
|
||||
ErrorField: "users",
|
||||
ErrorMsg: translator.TrWithData(handler.GetLangByCtx(ctx), reason.AddBulkUsersFormatError, errorData),
|
||||
})
|
||||
return nil, errFields, errors.BadRequest(reason.RequestFormatError)
|
||||
}
|
||||
return users, nil, nil
|
||||
}
|
||||
|
||||
// UpdateUserPassword update user password
|
||||
func (us *UserAdminService) UpdateUserPassword(ctx context.Context, req *schema.UpdateUserPasswordReq) (err error) {
|
||||
// Users cannot modify their password
|
||||
|
||||
Reference in New Issue
Block a user