This commit is contained in:
suguo 2026-03-19 17:35:11 +08:00
parent 3f5d062ee8
commit 6fff6d35a5
13 changed files with 571 additions and 183 deletions

View File

@ -15,7 +15,6 @@ func routerSetup(router *gin.Engine) {
protected.Use(auth(), authorize())
protected.POST("/logout", handler.AuthLogout)
protected.GET("/me", handler.AuthMe)
protected.POST("/password", handler.AuthChangePassword)
protected.GET("/orgs", handler.OrgList)
protected.POST("/orgs", handler.OrgCreate)
@ -55,4 +54,11 @@ func routerSetup(router *gin.Engine) {
protected.GET("/menus", handler.MenuList)
protected.GET("/options", handler.OptionMap)
protected.GET("/users", handler.UserList)
protected.POST("/users", handler.UserCreate)
protected.GET("/users/:id", handler.UserGet)
protected.PUT("/users/:id", handler.UserUpdate)
protected.DELETE("/users/:id", handler.UserDelete)
protected.PUT("/users/:id/password", handler.UserPasswordUpdate)
}

View File

@ -2,7 +2,6 @@ package handler
import (
"net/http"
"os"
"strings"
"github.com/gin-gonic/gin"
@ -88,60 +87,3 @@ func AuthMe(c *gin.Context) {
"user": usr,
})
}
func AuthChangePassword(c *gin.Context) {
usr := currentUser(c)
if usr == nil {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"data": "无效TOKEN, 请重新登录!",
})
return
}
var req AuthChangePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"data": "参数错误",
})
return
}
req.OldPassword = strings.TrimSpace(req.OldPassword)
req.NewPassword = strings.TrimSpace(req.NewPassword)
err := service.AuthChangePassword(usr.ID, req.OldPassword, req.NewPassword)
if err != nil {
switch err {
case service.ErrInvalidArgument:
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"data": "密码不能为空",
})
case service.ErrNewPasswordShort:
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"data": "新密码至少6位",
})
case service.ErrOldPasswordWrong:
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{
"data": "旧密码错误",
})
case service.ErrUserNotFound:
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"data": "无效用户, 请重新登录!",
})
default:
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
"data": authChangePasswordInternalError(err),
})
}
return
}
c.JSON(http.StatusOK, gin.H{
"data": "ok",
})
}
func authChangePasswordInternalError(err error) string {
if os.Getenv("DEBUG") == "true" && err != nil {
return "修改失败: " + err.Error()
}
return "修改失败"
}

View File

@ -1 +1,129 @@
package handler
import (
"net/http"
"strconv"
"github.com/gin-gonic/gin"
"myschools.me/heritage/heritage-api/service"
)
// UserCreate 创建用户
func UserCreate(c *gin.Context) {
var req service.UserCreateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "参数错误"})
return
}
user, err := service.UserCreate(req)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, service.UserResponse{User: user})
}
// UserUpdate 更新用户
func UserUpdate(c *gin.Context) {
userID := c.Param("id")
if userID == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "用户ID不能为空"})
return
}
var req service.UserUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "参数错误"})
return
}
user, err := service.UserUpdate(userID, req)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, service.UserResponse{User: user})
}
// UserDelete 删除用户
func UserDelete(c *gin.Context) {
userID := c.Param("id")
if userID == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "用户ID不能为空"})
return
}
success, err := service.UserDelete(userID)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": success})
}
// UserGet 获取用户
func UserGet(c *gin.Context) {
userID := c.Param("id")
if userID == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "用户ID不能为空"})
return
}
user, err := service.UserGet(userID)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, service.UserResponse{User: user})
}
// UserList 获取用户列表
func UserList(c *gin.Context) {
// 获取分页参数
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
// 确保分页参数有效
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 100 {
pageSize = 10
}
users, total, err := service.UserList(page, pageSize)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, service.UserListResponse{Users: users, Total: total})
}
// UserPasswordUpdate 更新用户密码
func UserPasswordUpdate(c *gin.Context) {
userID := c.Param("id")
if userID == "" {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "用户ID不能为空"})
return
}
var req service.UserPasswordUpdateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": "参数错误"})
return
}
err := service.UserPasswordUpdate(userID, req)
if err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"data": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"data": "密码更新成功"})
}

View File

@ -9,7 +9,7 @@ type Menu struct {
Name string `json:"name"`
Icon string `json:"icon"`
Path string `json:"path"`
Sort int `json:"sort"`
PermissionCode string `json:"permissionCode"`
Sort int `json:"-"`
PermissionCode string `json:"-"`
Children []*Menu `json:"children" gorm:"-"`
}

View File

@ -2,8 +2,11 @@ package model
type User struct {
ID string `json:"id" gorm:"type:varchar(32);primaryKey"`
UserName string `json:"userName" gorm:"type:varchar(20);not null;uniqueIndex"`
Avatar string `json:"avatar" gorm:"type:varchar(255);not null;default:''"`
UserName string `json:"userName" gorm:"type:varchar(20);not null"`
Mobile string `json:"mobile" gorm:"type:varchar(11);not null;uniqueIndex"`
PasswordHash string `json:"-" gorm:"type:varchar(128);default:''"`
RoleID string `json:"roleId" gorm:"type:varchar(32);index"`
Role Role `json:"role" gorm:"foreignKey:RoleID;references:ID"`
OrgID string `json:"orgId" gorm:"type:varchar(32);not null;index"`
}

View File

@ -72,3 +72,17 @@ func OrgList(parentID *string, offset, limit *int) ([]model.Org, int64, error) {
}
return items, total, nil
}
func OrgCount() (*int64, error) {
db, err := newDB()
if err != nil {
return nil, err
}
var count int64
if err := db.Model(&model.Org{}).Count(&count).Error; err != nil {
return nil, err
}
return &count, nil
}

View File

@ -7,48 +7,35 @@ import (
"myschools.me/heritage/heritage-api/model"
)
func UserByUserName(userName *string) (*model.User, bool, error) {
func UserByUserName(userName *string) (*model.User, error) {
db, err := newDB()
if err != nil {
return nil, false, err
return nil, err
}
var u model.User
if err := db.Where("user_name = ?", *userName).First(&u).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
if err != gorm.ErrRecordNotFound {
return nil, nil
}
return nil, false, err
}
return &u, true, nil
return &u, nil
}
func UserByID(userID *string) (*model.User, bool, error) {
// 获取单个用户信息,用户存在与否根据返回结果判断
func UserFirst(userID *string) (*model.User, error) {
db, err := newDB()
if err != nil {
return nil, false, err
return nil, err
}
var u model.User
if err := db.Where("id = ?", *userID).First(&u).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, nil
if err != gorm.ErrRecordNotFound {
return nil, err
}
return nil, false, err
}
return &u, true, nil
}
func UpdateUserPasswordHash(userID, passwordHash *string) (bool, error) {
db, err := newDB()
if err != nil {
return false, err
}
tx := db.Model(&model.User{}).Where("id = ?", *userID).Update("password_hash", *passwordHash)
if tx.Error != nil {
return false, tx.Error
}
return tx.RowsAffected > 0, nil
return &u, nil
}
func UserRoleIDByUserID(userID *string) (*string, bool, error) {
@ -90,3 +77,36 @@ func UserCreate(obj *model.User) (*model.User, error) {
}
return obj, nil
}
func UserList(page, pageSize int) ([]model.User, int64, error) {
db, err := newDB()
if err != nil {
return nil, 0, err
}
var users []model.User
var total int64
// 统计总数
if err := db.Model(&model.User{}).Count(&total).Error; err != nil {
return nil, 0, err
}
// 分页查询
offset := (page - 1) * pageSize
if err := db.Offset(offset).Limit(pageSize).Find(&users).Error; err != nil {
return nil, 0, err
}
return users, total, nil
}
// 用户更新可以更新所有项不作限制由service层判断
func UserUpdate(userID *string, obj map[string]any) error {
db, err := newDB()
if err != nil {
return err
}
return db.Model(&model.User{}).Where("id = ?", *userID).Updates(obj).Error
}

52
redis/menu-redis.go Normal file
View File

@ -0,0 +1,52 @@
package redis
import (
"encoding/json"
"fmt"
"time"
"myschools.me/heritage/heritage-api/model"
"github.com/sirupsen/logrus"
)
// MenuListKey 菜单列表缓存键
var MenuListKey = "menu:list_%s"
// MenuListSet 将菜单列表放入缓存
func MenuListSet(obj *string, menus []*model.Menu, expireIn time.Duration) error {
key := fmt.Sprintf(MenuListKey, *obj)
err := set(&key, menus, expireIn)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "MenuListSet",
}).Warnf("Set: %s", err.Error())
return err
}
return nil
}
// MenuListGet 从缓存中获取菜单列表
func MenuListGet(obj *string) ([]*model.Menu, error) {
key := fmt.Sprintf(MenuListKey, *obj)
b, err := getBytes(&key)
if err != nil {
return nil, err
}
if b == nil {
return nil, nil
}
var menus []*model.Menu
if err := json.Unmarshal(*b, &menus); err != nil {
return nil, err
}
return menus, nil
}
// MenuListDel 删除菜单列表缓存
func MenuListDel(obj *string) error {
key := fmt.Sprintf(MenuListKey, *obj)
return delete(key)
}

View File

@ -24,24 +24,24 @@ func AuthLogin(userName, plainPassword string) (string, *model.User, error) {
return "", nil, ErrInvalidCredentials
}
u, found, err := mysql.UserByUserName(&userName)
u, err := mysql.UserByUserName(&userName)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "service.Login",
"func": "AuthLogin",
"userName": userName,
}).Errorf("mysql.UserByUserName: %s", err.Error())
return "", nil, err
}
if !found || u == nil || u.PasswordHash == "" {
if u == nil || u.PasswordHash == "" {
logrus.WithFields(logrus.Fields{
"func": "service.AuthLogin",
"func": "AuthLogin",
"userName": userName,
}).Warnf("user not found or password not set")
return "", nil, ErrInvalidCredentials
}
if !PasswordVerify(u.PasswordHash, plainPassword) {
logrus.WithFields(logrus.Fields{
"func": "service.AuthLogin",
"func": "AuthLogin",
"userName": userName,
}).Warnf("password verification failed")
return "", nil, ErrInvalidCredentials
@ -52,10 +52,11 @@ func AuthLogin(userName, plainPassword string) (string, *model.User, error) {
ID: u.ID,
UserName: u.UserName,
RoleID: u.RoleID,
OrgID: u.OrgID,
}
if err := redis.UserTokenSet(&token, safeUser); err != nil {
logrus.WithFields(logrus.Fields{
"func": "service.Login",
"func": "AuthLogin",
"userID": u.ID,
}).Errorf("redis.UserTokenSet: %s", err.Error())
return "", nil, err
@ -72,60 +73,3 @@ func AuthLogout(token string) error {
}
return redis.UserTokenDel(&token)
}
func AuthChangePassword(userID, oldPassword, newPassword string) error {
oldPassword = strings.TrimSpace(oldPassword)
newPassword = strings.TrimSpace(newPassword)
if oldPassword == "" || newPassword == "" {
return ErrInvalidArgument
}
if len(newPassword) < 6 {
return ErrNewPasswordShort
}
dbUser, found, err := mysql.UserByID(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "service.ChangePassword",
"userID": userID,
}).Errorf("mysql.UserByID: %s", err.Error())
return err
}
if !found || dbUser == nil || dbUser.PasswordHash == "" {
logrus.WithFields(logrus.Fields{
"func": "service.AuthChangePassword",
"userID": userID,
}).Warnf("user not found")
return ErrUserNotFound
}
if !PasswordVerify(dbUser.PasswordHash, oldPassword) {
logrus.WithFields(logrus.Fields{
"func": "service.AuthChangePassword",
"userID": userID,
}).Warnf("old password verification failed")
return ErrOldPasswordWrong
}
hash, err := PasswordHash(newPassword)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "service.ChangePassword",
"userID": userID,
}).Errorf("password.HashPassword: %s", err.Error())
return err
}
updated, err := mysql.UpdateUserPasswordHash(&userID, &hash)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "service.ChangePassword",
"userID": userID,
}).Errorf("mysql.UpdateUserPasswordHash: %s", err.Error())
return err
}
if !updated {
return ErrUserNotFound
}
return nil
}

View File

@ -20,16 +20,16 @@ func newUserID() string {
// 专给机构创建用的ID20位
func newOrgID() string {
i := uuid.Must(uuid.NewV7()).String()
return strings.ReplaceAll(i, "-", "")[:20]
return strings.ReplaceAll(i, "-", "")[12:]
}
// 项目ID22位
func newProjectID() string {
i := uuid.Must(uuid.NewV7()).String()
return strings.ReplaceAll(i, "-", "")[:20]
return strings.ReplaceAll(i, "-", "")[10:]
}
func newToken() string {
i := uuid.Must(uuid.NewV7()).String()
i := uuid.Must(uuid.NewUUID()).String()
return strings.ReplaceAll(i, "-", "")
}

View File

@ -87,33 +87,60 @@ func Bootstrap() {
}
}
userCount, err := mysql.UserCount()
// 初始化管理机构
orgCount, err := mysql.OrgCount()
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("mysql.UserCount: %v", err)
}).Warnf("mysql.OrgCount: %v", err)
panic(err)
}
if *userCount == 0 {
defaultPwd := "admin"
h, err := bcrypt.GenerateFromPassword([]byte(defaultPwd), bcrypt.DefaultCost)
if *orgCount == 0 {
orgid := newOrgID()
// 创建管理机构
adminOrg := &model.Org{
ID: orgid,
Code: "admin",
Name: "管理机构",
OrgType: "admin",
ParentID: "0",
}
if err := mysql.OrgCreate(adminOrg); err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("mysql.OrgCreate: %v", err)
panic(err)
}
userCount, err := mysql.UserCount()
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("bcrypt.GenerateFromPassword: %v", err)
}).Warnf("mysql.UserCount: %v", err)
panic(err)
}
u := &model.User{
ID: newUserID(),
UserName: "admin",
PasswordHash: string(h),
RoleID: defaultRole.ID,
}
if _, err := mysql.UserCreate(u); err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("mysql.UserCreate: %v", err)
panic(err)
if *userCount == 0 {
defaultPwd := "admin"
h, err := bcrypt.GenerateFromPassword([]byte(defaultPwd), bcrypt.DefaultCost)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("bcrypt.GenerateFromPassword: %v", err)
panic(err)
}
u := &model.User{
ID: newUserID(),
UserName: "admin",
PasswordHash: string(h),
RoleID: defaultRole.ID,
OrgID: orgid,
}
if _, err := mysql.UserCreate(u); err != nil {
logrus.WithFields(logrus.Fields{
"func": "Bootstrap",
}).Warnf("mysql.UserCreate: %v", err)
panic(err)
}
}
}

View File

@ -1,26 +1,29 @@
package service
import (
"time"
"github.com/sirupsen/logrus"
"myschools.me/heritage/heritage-api/model"
"myschools.me/heritage/heritage-api/mysql"
"myschools.me/heritage/heritage-api/redis"
)
func MenuList(usr *model.User) ([]*model.Menu, error) {
// 获取用户角色 ID
roleID, found, err := mysql.UserRoleIDByUserID(&usr.ID)
// 先从缓存中获取角色对应的菜单列表
allMenus, err := redis.MenuListGet(&usr.RoleID)
if err == nil && len(allMenus) > 0 {
return allMenus, nil
}
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "MenuList",
}).Warnf("mysql.UserRoleIDByUserID: %v", err)
return nil, err
}
if !found {
return nil, nil
}).Warnf("redis.MenuListGet: %v", err)
}
// 获取角色拥有的所有权限
permissionCodes, err := mysql.RolePermissionsList(roleID)
permissionCodes, err := mysql.RolePermissionsList(&usr.RoleID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "MenuList",
@ -28,8 +31,8 @@ func MenuList(usr *model.User) ([]*model.Menu, error) {
return nil, err
}
// 获取所有菜单
allMenus, err := mysql.MenuList()
// 缓存中没有菜单,从数据库获取
menus, err := mysql.MenuList()
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "MenuList",
@ -49,13 +52,22 @@ func MenuList(usr *model.User) ([]*model.Menu, error) {
// 过滤有权限的菜单
var filteredMenus []*model.Menu
for i := range allMenus {
if hasPermission(allMenus[i].PermissionCode) {
filteredMenus = append(filteredMenus, &allMenus[i])
for i := range menus {
if hasPermission(menus[i].PermissionCode) {
filteredMenus = append(filteredMenus, &menus[i])
}
}
return menuTreeBuild(filteredMenus, 0), nil
menutree := menuTreeBuild(filteredMenus, 0)
// 将菜单列表放入缓存
if err := redis.MenuListSet(&usr.RoleID, menutree, 60*time.Second); err != nil {
logrus.WithFields(logrus.Fields{
"func": "MenuList",
}).Warnf("redis.MenuListSet: %v", err)
// 缓存设置失败,不影响返回结果
}
return menutree, nil
}
func menuTreeBuild(menus []*model.Menu, parentID uint) []*model.Menu {

240
service/user-service.go Normal file
View File

@ -0,0 +1,240 @@
package service
import (
"errors"
"github.com/sirupsen/logrus"
"golang.org/x/crypto/bcrypt"
"myschools.me/heritage/heritage-api/model"
"myschools.me/heritage/heritage-api/mysql"
)
// UserCreateRequest 创建用户请求
type UserCreateRequest struct {
UserName string `json:"userName" binding:"required"`
Password string `json:"password" binding:"required"`
RoleID string `json:"roleId" binding:"required"`
OrgID string `json:"orgId" binding:"required"`
}
// UserUpdateRequest 更新用户请求
type UserUpdateRequest struct {
UserName string `json:"userName"`
RoleID string `json:"roleId"`
OrgID string `json:"orgId"`
}
// UserPasswordUpdateRequest 更新密码请求
type UserPasswordUpdateRequest struct {
OldPassword string `json:"oldPassword" binding:"required"`
NewPassword string `json:"newPassword" binding:"required"`
}
// UserResponse 用户响应
type UserResponse struct {
User *model.User `json:"user"`
}
// UserListResponse 用户列表响应
type UserListResponse struct {
Users []model.User `json:"users"`
Total int64 `json:"total"`
}
// UserCreate 创建用户
func UserCreate(req UserCreateRequest) (*model.User, error) {
// 检查用户名是否已存在
existingUser, err := mysql.UserByUserName(&req.UserName)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserCreate",
}).Warnf("mysql.UserByUserName: %v", err)
return nil, err
}
if existingUser != nil && existingUser.ID != "" {
return nil, errors.New("用户名已存在")
}
// 密码加密
h, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserCreate",
}).Warnf("bcrypt.GenerateFromPassword: %v", err)
return nil, err
}
// 创建用户
user := &model.User{
ID: newUserID(),
UserName: req.UserName,
PasswordHash: string(h),
RoleID: req.RoleID,
OrgID: req.OrgID,
}
createdUser, err := mysql.UserCreate(user)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserCreate",
}).Warnf("mysql.UserCreate: %v", err)
return nil, err
}
return createdUser, nil
}
// UserUpdate 更新用户
func UserUpdate(userID string, req UserUpdateRequest) (*model.User, error) {
// 检查用户是否存在
existingUser, err := mysql.UserFirst(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserUpdate",
}).Warnf("mysql.UserFirst: %v", err)
return nil, err
}
if existingUser.ID == "" {
return nil, errors.New("用户不存在")
}
// 检查用户名是否已被其他用户使用
if req.UserName != "" && req.UserName != existingUser.UserName {
otherUser, err := mysql.UserByUserName(&req.UserName)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserUpdate",
}).Warnf("mysql.UserByUserName: %v", err)
return nil, err
}
if otherUser != nil && otherUser.ID != userID {
return nil, errors.New("用户名已存在")
}
}
// 构建更新数据
updateData := make(map[string]any)
if req.UserName != "" {
updateData["user_name"] = req.UserName
}
if req.RoleID != "" {
updateData["role_id"] = req.RoleID
}
if req.OrgID != "" {
updateData["org_id"] = req.OrgID
}
// 更新用户
if err := mysql.UserUpdate(&userID, updateData); err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserUpdate",
}).Warnf("mysql.UserUpdate: %v", err)
return nil, err
}
// 获取更新后的用户
updatedUser, err := mysql.UserFirst(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserUpdate",
}).Warnf("mysql.UserFirst: %v", err)
return nil, err
}
if updatedUser.ID == "" {
return nil, errors.New("用户不存在")
}
return updatedUser, nil
}
// UserDelete 删除用户
func UserDelete(userID string) (bool, error) {
// 检查用户是否存在
existingUser, err := mysql.UserFirst(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserDelete",
}).Warnf("mysql.UserFirst: %v", err)
return false, err
}
if existingUser.ID == "" {
return false, errors.New("用户不存在")
}
// 这里可以添加删除用户的逻辑
// 例如:软删除或硬删除
// 由于当前 mysql 包中没有提供删除用户的函数,我们可以先返回一个错误
return false, errors.New("删除用户功能暂未实现")
}
// UserGet 获取用户
func UserGet(userID string) (*model.User, error) {
// 检查用户是否存在
user, err := mysql.UserFirst(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserGet",
}).Warnf("mysql.UserFirst: %v", err)
return nil, err
}
if user.ID == "" {
return nil, errors.New("用户不存在")
}
return user, nil
}
// UserList 获取用户列表
func UserList(page, pageSize int) ([]model.User, int64, error) {
// 获取所有用户
users, total, err := mysql.UserList(page, pageSize)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserList",
}).Warnf("mysql.UserList: %v", err)
return nil, 0, err
}
return users, total, nil
}
// UserPasswordUpdate 更新用户密码
func UserPasswordUpdate(userID string, req UserPasswordUpdateRequest) error {
// 检查用户是否存在
user, err := mysql.UserFirst(&userID)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserPasswordUpdate",
}).Warnf("mysql.UserFirst: %v", err)
return err
}
if user.ID == "" {
return errors.New("用户不存在")
}
// 验证旧密码
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.OldPassword))
if err != nil {
return errors.New("旧密码错误")
}
// 密码加密
h, err := bcrypt.GenerateFromPassword([]byte(req.NewPassword), bcrypt.DefaultCost)
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserPasswordUpdate",
}).Warnf("bcrypt.GenerateFromPassword: %v", err)
return err
}
// 更新密码
err = mysql.UserUpdate(&userID, map[string]any{"password_hash": string(h)})
if err != nil {
logrus.WithFields(logrus.Fields{
"func": "UserPasswordUpdate",
}).Warnf("mysql.UserUpdate: %v", err)
return err
}
return nil
}