Files
kra-new/internal/service/business/account.go
T

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})
}