181 lines
6.2 KiB
Go
181 lines
6.2 KiB
Go
package business
|
|
|
|
import (
|
|
"context"
|
|
"net/mail"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
"unicode/utf8"
|
|
|
|
"kra/internal/biz/business"
|
|
"kra/internal/service/dto"
|
|
)
|
|
|
|
type AccountUsecase interface {
|
|
List(context.Context, business.AccountFilter, ...business.ListOption) ([]*business.Account, int64, error)
|
|
Find(context.Context, uint) (*business.Account, error)
|
|
CreateChild(context.Context, *business.Account) (*business.Account, error)
|
|
Update(context.Context, *business.AccountUpdate) error
|
|
}
|
|
type AccountService struct{ uc AccountUsecase }
|
|
|
|
func NewAccountService(uc *business.AccountUsecase) *AccountService { return &AccountService{uc: uc} }
|
|
|
|
func accountResponse(a *business.Account) *dto.BusinessAccountResponse {
|
|
return &dto.BusinessAccountResponse{UserID: a.ID, Username: a.Username, NickName: a.NickName, RealName: a.RealName, Phone: a.Phone, Email: a.Email, QQNumber: a.QQNumber,
|
|
Level: a.Level, ParentID: a.ParentID, IDPath: a.IDPath, ParentUserName: a.ParentUserName, Status: strconv.Itoa(a.Status), RejectReason: a.RejectReason, AuthorityID: a.AuthorityID,
|
|
CreateTime: a.CreatedAt.Format("2006-01-02 15:04:05"), UpdateTime: a.UpdatedAt.Format("2006-01-02 15:04:05"), PromoteCount: a.PromoteCount, BindCount: a.BindCount}
|
|
}
|
|
|
|
func (s *AccountService) List(ctx context.Context, req *dto.BusinessAccountQuery) (*dto.BusinessAccountPage, error) {
|
|
if req == nil {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
page, size := req.Page, req.PageSize
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if size < 1 {
|
|
size = 10
|
|
}
|
|
if size > 500 {
|
|
size = 500
|
|
}
|
|
if page > int(^uint(0)>>1)/size {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
filter := business.AccountFilter{UserID: req.UserID, Username: req.Username, NickName: req.NickName, RealName: req.RealName, Phone: req.Phone}
|
|
for _, field := range []struct {
|
|
raw string
|
|
target **int
|
|
}{{req.Level, &filter.Level}, {req.Status, &filter.Status}} {
|
|
if field.raw == "" {
|
|
continue
|
|
}
|
|
n, err := strconv.Atoi(field.raw)
|
|
if err != nil || n < 0 || n > 3 {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
*field.target = &n
|
|
}
|
|
if (req.BeginTime == "") != (req.EndTime == "") {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
if req.BeginTime != "" && req.EndTime != "" {
|
|
begin, err := time.ParseInLocation("2006-01-02 15:04:05", req.BeginTime, time.Local)
|
|
if err != nil {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
end, err := time.ParseInLocation("2006-01-02 15:04:05", req.EndTime, time.Local)
|
|
if err != nil || end.Before(begin) {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
filter.BeginTime, filter.EndTime = &begin, &end
|
|
}
|
|
rows, total, err := s.uc.List(ctx, filter, business.ListOffset((page-1)*size), business.ListLimit(size), business.ListOrderBy(req.OrderByColumn, strings.EqualFold(req.IsAsc, "desc") || req.IsAsc == "descending"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
out := &dto.BusinessAccountPage{Rows: make([]*dto.BusinessAccountResponse, 0, len(rows)), Total: total}
|
|
for _, a := range rows {
|
|
out.Rows = append(out.Rows, accountResponse(a))
|
|
}
|
|
return out, nil
|
|
}
|
|
func (s *AccountService) Find(ctx context.Context, id uint) (*dto.BusinessAccountResponse, error) {
|
|
if id == 0 {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
a, err := s.uc.Find(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return accountResponse(a), nil
|
|
}
|
|
|
|
func validateAccount(req *dto.BusinessAccountRequest, create bool) (*int, error) {
|
|
if req == nil {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
if create && req.HireDate == nil {
|
|
return nil, business.ErrMemberInput
|
|
}
|
|
if req.Phone != nil && !validMemberPhone(*req.Phone) {
|
|
return nil, business.ErrMemberInput
|
|
}
|
|
if req.HireDate != nil {
|
|
if _, err := time.Parse("2006-01-02", *req.HireDate); err != nil {
|
|
return nil, business.ErrMemberInput
|
|
}
|
|
}
|
|
if create && (req.Username == nil || req.RealName == nil || strings.TrimSpace(*req.RealName) == "" || req.Password == "") {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
if req.Username != nil && (utf8.RuneCountInString(*req.Username) < 2 || utf8.RuneCountInString(*req.Username) > 30 || strings.TrimSpace(*req.Username) == "") {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
for _, field := range []struct {
|
|
s *string
|
|
max int
|
|
}{{req.NickName, 30}, {req.RealName, 30}, {req.Phone, 20}, {req.Email, 50}, {req.QQNumber, 20}, {req.RejectReason, 200}} {
|
|
if field.s != nil && (utf8.RuneCountInString(*field.s) > field.max || strings.ContainsAny(*field.s, "<>")) {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
}
|
|
if req.Username != nil && strings.ContainsAny(*req.Username, "<>") {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
if create && (utf8.RuneCountInString(req.Password) < 5 || utf8.RuneCountInString(req.Password) > 50 || len(req.Password) > 72) {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
if req.Email != nil && *req.Email != "" {
|
|
if _, err := mail.ParseAddress(*req.Email); err != nil {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
}
|
|
if req.Status == nil {
|
|
return nil, nil
|
|
}
|
|
status, err := strconv.Atoi(*req.Status)
|
|
if err != nil || status < 0 || status > 3 {
|
|
return nil, business.ErrAccountInput
|
|
}
|
|
return &status, nil
|
|
}
|
|
|
|
func stringValue(s *string) string {
|
|
if s == nil {
|
|
return ""
|
|
}
|
|
return *s
|
|
}
|
|
|
|
func (s *AccountService) Create(ctx context.Context, req *dto.BusinessAccountRequest) (*dto.BusinessAccountResponse, error) {
|
|
status, err := validateAccount(req, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
a := &business.Account{Username: stringValue(req.Username), NickName: stringValue(req.NickName), RealName: stringValue(req.RealName), Phone: stringValue(req.Phone),
|
|
Email: stringValue(req.Email), QQNumber: stringValue(req.QQNumber), Password: req.Password, RejectReason: stringValue(req.RejectReason)}
|
|
a.HireDate = stringValue(req.HireDate)
|
|
if status != nil {
|
|
a.Status = *status
|
|
}
|
|
created, err := s.uc.CreateChild(ctx, a)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return accountResponse(created), nil
|
|
}
|
|
func (s *AccountService) Update(ctx context.Context, req *dto.BusinessAccountRequest) error {
|
|
status, err := validateAccount(req, false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if req.UserID == 0 {
|
|
return business.ErrAccountInput
|
|
}
|
|
return s.uc.Update(ctx, &business.AccountUpdate{ID: req.UserID, Username: req.Username, NickName: req.NickName, RealName: req.RealName, Phone: req.Phone, Email: req.Email, QQNumber: req.QQNumber, Status: status, RejectReason: req.RejectReason})
|
|
}
|