yintai2/app/admin/service/user.go

285 lines
6.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"fmt"
"strings"
"time"
"yintai-api/app/admin/request"
"yintai-api/app/common/cache"
"yintai-api/app/common/dao"
err2 "yintai-api/app/common/err"
"yintai-api/app/common/model"
"yintai-api/base/global"
"github.com/smbrave/goutil"
"github.com/spf13/cast"
"gorm.io/gorm"
)
type User struct {
user *model.UserWithRole
}
func NewUser(u *model.UserWithRole) *User {
return &User{user: u}
}
func (a *User) Create(req request.UserCreate) int64 {
// 通过 account 判断用户是否存在
exist, err := dao.NewUser().AccountExists(req.Account)
if err != nil {
err2.DbErr("<admin service create>", err)
}
if exist {
err2.EsxErr()
}
req.Password = strings.TrimSpace(req.Password)
checkPassword(req.Password)
if cast.ToInt64(req.Role) != 0 {
// 检查 role 是否存在
exist, err = dao.NewRole().Exists(cast.ToInt64(req.Role))
if err != nil {
err2.DbErr("<admin service create>", err)
}
if !exist {
err2.NotEsxErr("<admin service create> check role")
}
}
// 通过事务来创建账号以及分配用户角色
m := new(model.User)
m.Username = req.Username
m.Account = req.Account
m.Password = goutil.Md5(req.Password + model.Salt)
m.CreateTime = time.Now().Unix()
m.Status = model.UserStatusNormal
err = global.GetDB().Transaction(func(tx *gorm.DB) error {
if err = dao.NewUser(tx).Create(m); err != nil {
return err
}
if cast.ToInt64(req.Role) != 0 {
var role *model.Role
// 获取这个角色的页面和路由的所有权限
role, err = dao.NewRole(tx).Get(cast.ToInt64(req.Role))
if err != nil {
return err
}
m := new(model.UserRole)
m.UserID = cast.ToInt64(role.ID)
m.RoleID = cast.ToInt64(role.ID)
if err = dao.NewUserRole(tx).Create(m); err != nil {
return err
}
}
return nil
})
if err != nil {
err2.DbErr("<admin service create>", err)
}
return m.ID
}
func (a *User) Update(req request.UserUpdate) {
var user *model.User
var err error
user, err = dao.NewUser().AccountGet(a.user.Account)
if err != nil {
err2.DbErr("<user service update>", err)
}
if user == nil {
err2.NotEsxErr("<user service update>")
return
}
if req.Username != "" {
user.Username = req.Username
}
if cast.ToInt64(req.Status) != 0 {
user.Status = cast.ToInt64(req.Status)
}
if cast.ToInt64(req.Role) != 0 {
role, err := dao.NewRole().Exists(cast.ToInt64(req.Role))
if err != nil {
err2.DbErr("<user service update>", err)
}
if !role {
err2.NotEsxErr()
}
}
req.Password = strings.TrimSpace(req.Password)
if req.Password != "" {
checkPassword(req.Password)
user.Password = goutil.Md5(req.Password + model.Salt)
}
err = global.GetDB().Transaction(func(tx *gorm.DB) error {
if err = dao.NewUser(tx).Update(user); err != nil {
return err
}
if cast.ToInt64(req.Role) != 0 {
if err = dao.NewUserRole(tx).Delete(user.ID); err != nil {
return err
}
if err = dao.NewUserRole(tx).Create(&model.UserRole{UserID: user.ID, RoleID: cast.ToInt64(req.Role)}); err != nil {
return err
}
}
// 禁用即下线
if user.Status == model.UserStatusBaned {
a.expireByAccount(user.Account)
}
return nil
})
if err != nil {
err2.DbErr("<user service update>", err)
}
}
func checkPassword(password string) {
n := len([]rune(password))
if n < 8 || n > 16 {
err2.ParamErr("password length must be between 8 and 16")
}
var upper, lower, digit, special bool
for _, r := range password {
switch {
case r >= 'A' && r <= 'Z':
upper = true
case r >= 'a' && r <= 'z':
lower = true
case r >= '0' && r <= '9':
digit = true
default:
special = true
}
}
if !upper || !lower || !digit || !special {
err2.ParamErr("password must include uppercase, lowercase, digit and special character")
}
}
func (a *User) Delete(req request.UserDelete) {
var user *model.User
var err error
user, err = dao.NewUser().Get(cast.ToInt64(req.ID))
if err != nil {
err2.DbErr("<user service update>", err)
}
if user == nil {
err2.NotEsxErr("<user service update>")
return
}
if err = dao.NewUser().Delete(user.ID); err != nil {
err2.DbErr("<user service update>", err)
}
a.expireByAccount(user.Account)
return
}
func (a *User) List(req request.UserList) (any, int64) {
req.Pagination()
users, count, err := dao.NewUser().List(req.Username, req.Account, cast.ToInt64(req.Role), req.Page, req.Size, req.Sort)
if err != nil {
err2.DbErr("<users service list>", err)
}
res := make([]map[string]any, 0)
for _, m := range users {
res = append(res, m.Format())
}
return res, count
}
func (a *User) Login(req request.UserLogin) any {
verifyCaptcha(req.CaptchaID, req.Captcha)
user, err := dao.NewUser().GetWithRole(req.Account)
if err != nil {
err2.DbErr("<user service login>", err)
}
if user == nil {
err2.LoginErr()
return ""
}
if user.Password != goutil.Md5(req.Password+model.Salt) {
err2.LoginErr()
}
token := fmt.Sprintf("%s", goutil.RandomStr(64))
expire := time.Hour * 24 * 30
redix := cache.GetRedis()
key := cache.NewKeys().User() + token
if err = redix.Set(key, goutil.EncodeJSON(user), expire).Err(); err != nil {
err2.DbErr("<user service login>", err)
}
// 保存用户的user_id 到token
// 通过用户的account来创建一个 k-v account是key,其他的是value
if oldToken := redix.Get(cache.NewKeys().User2Token() + user.Account).Val(); oldToken != "" {
a.expire(oldToken)
}
redix.Set(cache.NewKeys().User2Token()+user.Account, token, expire)
resource, err := dao.NewResource().RoleGet(user.RoleID)
if err != nil {
err2.DbErr("<user service login>", err)
}
userResource := make([]map[string]any, 0)
for _, v := range resource {
if v.Type != "page" {
continue
}
userResource = append(userResource, v.Format())
}
res := make(map[string]any)
res["resource"] = userResource
res["token"] = token
return res
}
func (a *User) Logout(req request.UserLogout) {
a.expire(req.Token)
return
}
func (a *User) expireByAccount(account string) {
key := cache.NewKeys().User2Token() + account
token := cache.GetRedis().Get(key).Val()
if token == "" {
return
}
a.expire(token)
}
func (a *User) expire(token string) {
redix := cache.GetRedis()
key := cache.NewKeys().User() + token
redix.Del(key)
return
}