295 lines
8.0 KiB
Go
295 lines
8.0 KiB
Go
package services
|
||
|
||
import (
|
||
"Quincy_admin/repositories"
|
||
"Quincy_admin/schemas"
|
||
"Quincy_admin/utils"
|
||
"fmt"
|
||
"net"
|
||
"time"
|
||
|
||
"golang.org/x/crypto/bcrypt"
|
||
)
|
||
|
||
type UserService struct {
|
||
repo *repositories.UserRepository
|
||
}
|
||
|
||
func NewUserService(repo *repositories.UserRepository) (*UserService, error) {
|
||
service := &UserService{repo: repo}
|
||
return service, nil
|
||
}
|
||
|
||
// CreateUser 创建用户
|
||
func (s *UserService) CreateUser(userReq *schemas.CreateUser) error {
|
||
// 只有当密码不为空时才进行加密处理
|
||
if userReq.Password != "" {
|
||
hashedPassword, err := s.HashPassword(userReq.Password)
|
||
if err != nil {
|
||
return fmt.Errorf("密码加密失败: %v", err)
|
||
}
|
||
userReq.Password = hashedPassword
|
||
} else {
|
||
return fmt.Errorf("密码不能为空")
|
||
}
|
||
|
||
//添加默认值
|
||
userReq.RoleCode = 0
|
||
userReq.Status = schemas.UserStatusDisabled
|
||
|
||
// 如果 UserCode 为空,生成一个唯一的 UserCode,确保与数据库中已有的不重复
|
||
foundUniqueCode := false
|
||
for i := 0; i < 5; i++ { // 最多尝试5次
|
||
userReq.SessionCode = utils.GenerateUserCode("S10", 7)
|
||
// 检查数据库是否已存在该 sessioncode
|
||
count, err := s.repo.IsUserCodeExists(userReq.SessionCode)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if count == 0 {
|
||
foundUniqueCode = true
|
||
break
|
||
}
|
||
}
|
||
|
||
// 如果5次尝试后仍未找到唯一code,返回错误
|
||
if !foundUniqueCode {
|
||
return fmt.Errorf("无法生成唯一的用户编码,已尝试5次")
|
||
}
|
||
|
||
// 生成唯一的 Username,确保与数据库中已有的不重复
|
||
foundUniqueName := false
|
||
for i := 0; i < 5; i++ {
|
||
userReq.Username, _ = utils.GenerateUsername(8)
|
||
// 检查数据库是否已存在该 Username
|
||
count, err := s.repo.IsUsernameExists(userReq.Username)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if count == 0 {
|
||
foundUniqueName = true
|
||
break
|
||
}
|
||
}
|
||
|
||
// 如果5次尝试后仍未找到唯一username,返回错误
|
||
if !foundUniqueName {
|
||
return fmt.Errorf("无法生成唯一的用户名,已尝试5次")
|
||
}
|
||
|
||
return s.repo.Create(userReq)
|
||
}
|
||
|
||
// IsEmailExists 检查邮箱是否已存在
|
||
func (s *UserService) IsEmailExists(email string) (int, error) {
|
||
return s.repo.IsEmailExists(email)
|
||
}
|
||
|
||
// GetUserByID 通过用户ID查找用户
|
||
func (s *UserService) GetUserByID(scode string) (*schemas.UserInfo, error) {
|
||
return s.repo.FindByID(scode)
|
||
}
|
||
|
||
// GetUserByUsername 通过用户名查找用户
|
||
func (s *UserService) GetUserByUsername(username string) (*schemas.UserInfo, error) {
|
||
return s.repo.FindByUsername(username)
|
||
}
|
||
|
||
// GetUserLocation 获取用户地理位置信息
|
||
func (s *UserService) GetUserLocation(ipAddress string) (map[string]string, error) {
|
||
geoDB := utils.GetGeoIP()
|
||
if geoDB == nil {
|
||
return nil, fmt.Errorf("GeoIP database not initialized")
|
||
}
|
||
|
||
// 解析 IP 地址
|
||
ip := net.ParseIP(ipAddress)
|
||
if ip == nil {
|
||
return nil, fmt.Errorf("invalid IP address: %s", ipAddress)
|
||
}
|
||
|
||
// 查询地理位置
|
||
record, err := geoDB.City(ip)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("failed to query GeoIP database: %v", err)
|
||
}
|
||
|
||
// 构造返回结果
|
||
location := map[string]string{
|
||
"ip": ipAddress,
|
||
"country": record.Country.Names["zh-CN"],
|
||
"country_code": record.Country.IsoCode,
|
||
"province": "",
|
||
"city": "",
|
||
"latitude": fmt.Sprintf("%f", record.Location.Latitude),
|
||
"longitude": fmt.Sprintf("%f", record.Location.Longitude),
|
||
}
|
||
|
||
// 获取省份/州信息
|
||
if len(record.Subdivisions) > 0 {
|
||
location["province"] = record.Subdivisions[0].Names["zh-CN"]
|
||
}
|
||
|
||
// 获取城市信息
|
||
if record.City.Names["zh-CN"] != "" {
|
||
location["city"] = record.City.Names["zh-CN"]
|
||
}
|
||
|
||
//fmt.Println("location:", location)
|
||
|
||
return location, nil
|
||
}
|
||
|
||
// StoreLoginSession 存储登录会话
|
||
//func (s *UserService) StoreLoginSession(sessionKey string, userInfo *schemas.UserInfo, expireTime time.Duration) error {
|
||
// InitRedis := utils.GetRedis()
|
||
// ctx := utils.GetContext()
|
||
//
|
||
// // 将用户信息序列化后存储到Redis
|
||
// userInfoBytes, err := json.Marshal(userInfo)
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
//
|
||
// err = InitRedis.Set(ctx, sessionKey, userInfoBytes, expireTime).Err()
|
||
// if err != nil {
|
||
// return err
|
||
// }
|
||
//
|
||
// return nil
|
||
//}
|
||
|
||
// RecordLoginLog 记录登录日志
|
||
func (s *UserService) RecordLoginLog(userID int, username string, ipAddress string, userAgent string, status int, failureReason string) error {
|
||
// 获取地理位置信息
|
||
locationInfo, err := s.GetUserLocation("60.255.157.229")
|
||
var locationStr string
|
||
if err == nil {
|
||
locationStr = fmt.Sprintf("%s%s%s",
|
||
locationInfo["country"],
|
||
locationInfo["province"],
|
||
locationInfo["city"])
|
||
} else {
|
||
locationStr = "未知位置"
|
||
}
|
||
|
||
// 创建登录日志记录
|
||
now := time.Now()
|
||
loginLog := &schemas.LoginLog{
|
||
UserID: userID,
|
||
Username: username,
|
||
IPAddress: ipAddress,
|
||
Location: locationStr,
|
||
UserAgent: userAgent,
|
||
LoginTime: schemas.NewCustomTime(&now),
|
||
Status: status,
|
||
FailureReason: failureReason,
|
||
CreateTime: schemas.NewCustomTime(&now),
|
||
}
|
||
|
||
// 插入数据库
|
||
return s.repo.RecordLoginLog(loginLog)
|
||
}
|
||
|
||
// UpdateUser 更新用户信息
|
||
func (s *UserService) UpdateUser(user *schemas.UpdateUser) (int, error) {
|
||
// 检查是否尝试修改超级管理员账户(ID=1)
|
||
if user.ID == 1 {
|
||
return 0, fmt.Errorf("无法修改超级管理员账户信息")
|
||
}
|
||
|
||
// 只有当密码不为空时才进行加密处理
|
||
if user.Password != "" {
|
||
hashedPassword, err := s.HashPassword(user.Password)
|
||
if err != nil {
|
||
return 0, fmt.Errorf("密码加密失败: %v", err)
|
||
}
|
||
user.Password = hashedPassword
|
||
} else {
|
||
// 如果密码为空,则不更新密码字段
|
||
user.Password = ""
|
||
}
|
||
|
||
return s.repo.Update(user)
|
||
}
|
||
|
||
// UpdateLastLoginTime 更新用户最后登录时间
|
||
func (s *UserService) UpdateLastLoginTime(scode string) error {
|
||
return s.repo.UpdateLastLoginTime(scode, time.Now())
|
||
}
|
||
|
||
// UpdateStatus 删除用户
|
||
func (s *UserService) UpdateStatus(id int, enable int) error {
|
||
// 防止修改超级管理员账户(ID=1)
|
||
if id == 1 {
|
||
return fmt.Errorf("无权限修改超级管理员账户")
|
||
}
|
||
return s.repo.UpdateStatus(id, enable)
|
||
}
|
||
|
||
// HashPassword 对密码进行加密
|
||
func (s *UserService) HashPassword(password string) (string, error) {
|
||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return string(hashedPassword), nil
|
||
}
|
||
|
||
// VerifyPassword 验证密码
|
||
func (s *UserService) VerifyPassword(plainPassword, hashedPassword string) bool {
|
||
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(plainPassword))
|
||
return err == nil
|
||
}
|
||
|
||
// GetUserList 获取用户列表
|
||
func (s *UserService) GetUserList(req *schemas.UserListRequest) ([]*schemas.UserInfo, int64, error) {
|
||
return s.repo.GetUserList(req)
|
||
}
|
||
|
||
// GetRoleList 获取角色列表
|
||
func (s *UserService) GetRoleList(req *schemas.RoleListRequest) ([]*schemas.RoleResponseList, int64, error) {
|
||
return s.repo.GetRoleList(req)
|
||
}
|
||
|
||
// GetLoginLogList 获取登录日志列表
|
||
func (s *UserService) GetLoginLogList(req *schemas.LoginLogListRequest) ([]*schemas.LoginLog, int64, error) {
|
||
return s.repo.GetLoginLogList(req)
|
||
}
|
||
|
||
// AssignRole 分配角色
|
||
func (s *UserService) AssignRole(userIdValue, roleIdValue int) error {
|
||
// 检查用户是否已分配角色
|
||
exists, err := s.repo.AssignRoleExists(userIdValue)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if !exists {
|
||
// 用户未分配角色,执行插入操作
|
||
return s.repo.AssignRole(userIdValue, roleIdValue)
|
||
} else {
|
||
// 用户已分配角色,执行更新操作
|
||
return s.repo.UpdateAssignRole(userIdValue, roleIdValue)
|
||
}
|
||
}
|
||
|
||
// UpdateRoleStatus 删除用户
|
||
func (s *UserService) UpdateRoleStatus(id int, enable int) error {
|
||
// 防止修改超级管理员账户(ID=1)
|
||
if id == 1 {
|
||
return fmt.Errorf("无权限修改超级管理员账户")
|
||
}
|
||
return s.repo.UpdateRoleStatus(id, enable)
|
||
}
|
||
|
||
// CreateRole 创建角色
|
||
func (s *UserService) CreateRole(req *schemas.CreateRole) error {
|
||
return s.repo.CreateRole(req)
|
||
}
|
||
|
||
// UpdateRole 更新角色
|
||
func (s *UserService) UpdateRole(req *schemas.CreateRole) error {
|
||
return s.repo.UpdateRole(req)
|
||
}
|