package service import ( "crypto/sha512" "electricity_bill_calc/cache" "electricity_bill_calc/config" "electricity_bill_calc/exceptions" "electricity_bill_calc/global" "electricity_bill_calc/model" "electricity_bill_calc/repository" "electricity_bill_calc/utils" "fmt" "log" "strings" "time" "github.com/google/uuid" "github.com/mozillazg/go-pinyin" "xorm.io/builder" ) type _UserService struct{} var UserService _UserService func (_UserService) ProcessEnterpriseUserLogin(username, password string) (*model.Session, error) { user, err := repository.UserRepo.FindUserByUsername(username) if err != nil { return nil, err } if user == nil { return nil, exceptions.NewAuthenticationError(404, "用户不存在。") } if user.Type != 0 { return nil, exceptions.NewAuthenticationError(401, "用户类型不正确。") } if !user.Enabled { return nil, exceptions.NewAuthenticationError(401, "用户已被禁用。") } hash := sha512.New512_256() hash.Write([]byte(password)) hashedPassword := fmt.Sprintf("%x", hash.Sum(nil)) if hashedPassword != user.Password { return nil, exceptions.NewAuthenticationError(401, "用户凭据不正确。") } if user.ResetNeeded { authErr := exceptions.NewAuthenticationError(401, "用户凭据已失效。") authErr.NeedReset = true return nil, authErr } userDetial, _ := repository.UserRepo.RetreiveUserDetail(user.Id) if userDetial.ServiceExpiration.Before(time.Now()) { return nil, exceptions.NewAuthenticationError(401, "用户服务期限已过。") } session := &model.Session{ Token: uuid.New().String(), Uid: user.Id, Type: user.Type, Name: user.Username, ExpiresAt: time.Now().Add(config.ServiceSettings.MaxSessionLife), } if userDetial != nil { session.Name = *userDetial.Name } cache.CacheSession(session) return session, nil } func (_UserService) ProcessManagementUserLogin(username, password string) (*model.Session, error) { user, err := repository.UserRepo.FindUserByUsername(username) if err != nil { return nil, err } if user == nil { return nil, exceptions.NewAuthenticationError(404, "用户不存在。") } if user.Type != 1 && user.Type != 2 { return nil, exceptions.NewAuthenticationError(401, "用户类型不正确。") } if !user.Enabled { return nil, exceptions.NewAuthenticationError(401, "用户已被禁用。") } hash := sha512.New512_256() hash.Write([]byte(password)) hashedPassword := fmt.Sprintf("%x", hash.Sum(nil)) if hashedPassword != user.Password { return nil, exceptions.NewAuthenticationError(401, "用户凭据不正确。") } if user.ResetNeeded { authErr := exceptions.NewAuthenticationError(401, "用户凭据已失效。") authErr.NeedReset = true return nil, authErr } session := &model.Session{ Token: uuid.New().String(), Uid: user.Id, Type: user.Type, Name: user.Username, ExpiresAt: time.Now().Add(config.ServiceSettings.MaxSessionLife), } userDetial, _ := repository.UserRepo.RetreiveUserDetail(user.Id) if userDetial != nil { session.Name = *userDetial.Name } cache.CacheSession(session) return session, nil } func (_UserService) InvalidUserPassword(uid string) (string, error) { user, err := repository.UserRepo.FindUserByID(uid) if user == nil && err != nil { return "", exceptions.NewNotFoundError("指定的用户不存在。") } verifyCode := utils.RandStr(10) hash := sha512.New512_256() hash.Write([]byte(verifyCode)) user.Password = fmt.Sprintf("%x", hash.Sum(nil)) user.ResetNeeded = true affected, err := global.DBConn.ID(uid).Cols("password", "reset_needed").Update(user) if err != nil { return "", err } if affected > 0 { // ! 同一个用户在缓存中有两个键。 cache.AbolishCacheData("user", user.Id) cache.AbolishCacheData("user", user.Username) return verifyCode, nil } else { return "", exceptions.NewUnsuccessfulOperationError() } } func (_UserService) VerifyUserPassword(username, verifyCode string) (bool, error) { user, err := repository.UserRepo.FindUserByUsername(username) if user == nil || err != nil { return false, exceptions.NewNotFoundError("指定的用户不存在。") } hash := sha512.New512_256() hash.Write([]byte(verifyCode)) hashedVerifyCode := fmt.Sprintf("%x", hash.Sum(nil)) if hashedVerifyCode != user.Password { return false, nil } else { return true, nil } } func (_UserService) ResetUserPassword(username, password string) (bool, error) { user, err := repository.UserRepo.FindUserByUsername(username) if user == nil || err != nil { return false, exceptions.NewNotFoundError("指定的用户不存在。") } hash := sha512.New512_256() hash.Write([]byte(password)) user.Password = fmt.Sprintf("%x", hash.Sum(nil)) user.ResetNeeded = false affected, err := global.DBConn.ID(user.Id).Cols("password", "reset_needed").Update(user) if err != nil { return false, err } if affected > 0 { cache.AbolishCacheData("user", user.Id) cache.AbolishCacheData("user", user.Username) return true, nil } else { return false, nil } } func (_UserService) IsUserExists(uid string) (bool, error) { return global.DBConn.ID(uid).Exist(&model.User{}) } func (_UserService) IsUsernameExists(username string) (bool, error) { return global.DBConn.Where(builder.Eq{"username": username}).Exist(&model.User{}) } func (u _UserService) CreateUser(user *model.User, detail *model.UserDetail) (string, error) { if len(user.Id) == 0 { user.Id = uuid.New().String() } exists, err := u.IsUserExists(user.Id) if exists { return "", exceptions.NewNotFoundError("user already exists") } if err != nil { return "", nil } detail.Id = user.Id verifyCode := utils.RandStr(10) hash := sha512.New512_256() hash.Write([]byte(verifyCode)) user.Password = fmt.Sprintf("%x", hash.Sum(nil)) user.ResetNeeded = true if detail.Name != nil { abbr := pinyin.Pinyin(*detail.Name, pinyin.NewArgs()) var abbrCollect = make([]string, 0) for _, a := range abbr { abbrCollect = append(abbrCollect, a[0][0:1]) } finalAbbr := strings.Join(abbrCollect, "") detail.Abbr = &finalAbbr log.Printf("[service] [debug] detail: %v", detail) } tx := global.DBConn.NewSession() defer tx.Close() if err := tx.Begin(); err != nil { return "", err } _, err = tx.Insert(user) if err != nil { tx.Rollback() return "", fmt.Errorf("user create failed: %w", err) } _, err = tx.Insert(detail) if err != nil { tx.Rollback() return "", fmt.Errorf("user Detail create failed: %w", err) } err = tx.Commit() if err != nil { tx.Rollback() return "", fmt.Errorf("transaction commit unsuccessful: %w", err) } return verifyCode, nil } func (u _UserService) SwitchUserState(uid string, enabled bool) error { exists, err := u.IsUserExists(uid) if !exists { return exceptions.NewNotFoundError("user not exists") } if err != nil { return err } newStateUser := new(model.User) newStateUser.Enabled = enabled _, err = global.DBConn.ID(uid).Cols("enabled").Update(newStateUser) return err } func (_UserService) SearchLimitUsers(keyword string, limit int) ([]model.JoinedUserDetail, error) { var users = make([]model.JoinedUserDetail, 0) err := global.DBConn. Table("user_detail").Alias("d"). Join("INNER", []string{"user", "u"}, "d.id=u.id"). Where( builder.NewCond(). Or(builder.Like{"u.username", keyword}). Or(builder.Like{"d.name", keyword}). Or(builder.Like{"d.abbr", keyword})). And(builder.Eq{"u.type": 0}). Asc("u.created_at"). Limit(limit, 0). Find(&users) if err != nil { return make([]model.JoinedUserDetail, 0), err } return users, nil }