389 lines
12 KiB
Go
389 lines
12 KiB
Go
package service
|
|
|
|
import (
|
|
"electricity_bill_calc/cache"
|
|
"electricity_bill_calc/config"
|
|
"electricity_bill_calc/exceptions"
|
|
"electricity_bill_calc/global"
|
|
"electricity_bill_calc/model"
|
|
"electricity_bill_calc/tools"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/fufuok/utils"
|
|
"github.com/google/uuid"
|
|
"xorm.io/builder"
|
|
)
|
|
|
|
type _UserService struct{}
|
|
|
|
var UserService _UserService
|
|
|
|
func (u _UserService) ProcessEnterpriseUserLogin(username, password string) (*model.Session, error) {
|
|
user, err := u.findUserWithCredentialsByUsername(username)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if user == nil {
|
|
return nil, exceptions.NewAuthenticationError(404, "用户不存在。")
|
|
}
|
|
if user.Type != 0 {
|
|
return nil, exceptions.NewAuthenticationError(400, "用户类型不正确。")
|
|
}
|
|
if !user.Enabled {
|
|
return nil, exceptions.NewAuthenticationError(403, "用户已被禁用。")
|
|
}
|
|
hashedPassword := utils.Sha512Hex(password)
|
|
if hashedPassword != user.Password {
|
|
return nil, exceptions.NewAuthenticationError(402, "用户凭据不正确。")
|
|
}
|
|
if user.ResetNeeded {
|
|
authErr := exceptions.NewAuthenticationError(401, "用户凭据已失效。")
|
|
authErr.NeedReset = true
|
|
return nil, authErr
|
|
}
|
|
userDetial, _ := u.retreiveUserDetail(user.Id)
|
|
if userDetial.ServiceExpiration.Before(time.Now()) {
|
|
return nil, exceptions.NewAuthenticationError(406, "用户服务期限已过。")
|
|
}
|
|
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 (u _UserService) ProcessManagementUserLogin(username, password string) (*model.Session, error) {
|
|
user, err := u.findUserWithCredentialsByUsername(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, "用户已被禁用。")
|
|
}
|
|
hashedPassword := utils.Sha512Hex(password)
|
|
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, _ := u.retreiveUserDetail(user.Id)
|
|
if userDetial != nil {
|
|
session.Name = *userDetial.Name
|
|
}
|
|
cache.CacheSession(session)
|
|
return session, nil
|
|
}
|
|
|
|
func (u _UserService) InvalidUserPassword(uid string) (string, error) {
|
|
user, err := u.findUserByID(uid)
|
|
if user == nil && err != nil {
|
|
return "", exceptions.NewNotFoundError("指定的用户不存在。")
|
|
}
|
|
verifyCode := tools.RandStr(10)
|
|
user.Password = utils.Sha512Hex(verifyCode)
|
|
user.ResetNeeded = true
|
|
affected, err := global.DBConn.ID(uid).Cols("password", "reset_needed").Update(user)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if affected > 0 {
|
|
// ! 同一个用户在缓存中有两个键。
|
|
cache.AbolishRelation(fmt.Sprintf("user_%s", uid))
|
|
cache.AbolishRelation("user")
|
|
return verifyCode, nil
|
|
} else {
|
|
return "", exceptions.NewUnsuccessfulOperationError()
|
|
}
|
|
}
|
|
|
|
func (u _UserService) VerifyUserPassword(username, verifyCode string) (bool, error) {
|
|
user, err := u.findUserByUsername(username)
|
|
if user == nil || err != nil {
|
|
return false, exceptions.NewNotFoundError("指定的用户不存在。")
|
|
}
|
|
hashedVerifyCode := utils.Sha512Hex(verifyCode)
|
|
if hashedVerifyCode != user.Password {
|
|
return false, nil
|
|
} else {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
func (u _UserService) ResetUserPassword(username, password string) (bool, error) {
|
|
user, err := u.findUserByUsername(username)
|
|
if user == nil || err != nil {
|
|
return false, exceptions.NewNotFoundError("指定的用户不存在。")
|
|
}
|
|
user.Password = utils.Sha512Hex(password)
|
|
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.AbolishRelation(fmt.Sprintf("user_%s", user.Id))
|
|
cache.AbolishRelation("user")
|
|
return true, nil
|
|
} else {
|
|
return false, nil
|
|
}
|
|
}
|
|
|
|
func (_UserService) IsUserExists(uid string) (bool, error) {
|
|
if has, _ := cache.CheckExists("user", uid); has {
|
|
return has, nil
|
|
}
|
|
has, err := global.DBConn.ID(uid).Exist(&model.User{})
|
|
if has {
|
|
cache.CacheExists([]string{fmt.Sprintf("user_%s", uid)}, "user", uid)
|
|
}
|
|
return has, err
|
|
}
|
|
|
|
func (_UserService) IsUsernameExists(username string) (bool, error) {
|
|
if has, _ := cache.CheckExists("user", username); has {
|
|
return has, nil
|
|
}
|
|
has, err := global.DBConn.Where(builder.Eq{"username": username}).Exist(&model.User{})
|
|
if has {
|
|
cache.CacheExists([]string{"user"}, "user", username)
|
|
}
|
|
return has, err
|
|
}
|
|
|
|
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 := tools.RandStr(10)
|
|
user.Password = utils.Sha512Hex(verifyCode)
|
|
user.ResetNeeded = true
|
|
|
|
if detail.Name != nil {
|
|
finalAbbr := tools.PinyinAbbr(*detail.Name)
|
|
detail.Abbr = &finalAbbr
|
|
}
|
|
|
|
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)
|
|
}
|
|
cache.AbolishRelation("user")
|
|
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)
|
|
if err != nil {
|
|
cache.AbolishRelation("user")
|
|
cache.AbolishRelation(fmt.Sprintf("user_%s", uid))
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (_UserService) SearchLimitUsers(keyword string, limit int) ([]model.JoinedUserDetail, error) {
|
|
if cachedUsers, _ := cache.RetreiveSearch[[]model.JoinedUserDetail]("join_user_detail", keyword, strconv.Itoa(limit)); cachedUsers != nil {
|
|
return *cachedUsers, nil
|
|
}
|
|
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
|
|
}
|
|
cache.CacheSearch(users, []string{"user"}, "join_user_detail", keyword, strconv.Itoa(limit))
|
|
return users, nil
|
|
}
|
|
|
|
func (_UserService) findUserWithCredentialsByUsername(username string) (*model.UserWithCredentials, error) {
|
|
if cachedUser, _ := cache.RetreiveSearch[model.UserWithCredentials]("user_with_credentials", username); cachedUser != nil {
|
|
return cachedUser, nil
|
|
}
|
|
user := new(model.UserWithCredentials)
|
|
has, err := global.DBConn.Where(builder.Eq{"username": username}).NoAutoCondition().Get(user)
|
|
if has {
|
|
cache.CacheSearch(*user, []string{"user"}, "user_with_credentials", username)
|
|
}
|
|
return _postProcessSingle(user, has, err)
|
|
}
|
|
|
|
func (_UserService) findUserByUsername(username string) (*model.User, error) {
|
|
if cachedUser, _ := cache.RetreiveSearch[model.User]("user", username); cachedUser != nil {
|
|
return cachedUser, nil
|
|
}
|
|
user := new(model.User)
|
|
has, err := global.DBConn.Where(builder.Eq{"username": username}).NoAutoCondition().Get(user)
|
|
if has {
|
|
cache.CacheSearch(*user, []string{"user"}, "user", username)
|
|
}
|
|
return _postProcessSingle(user, has, err)
|
|
}
|
|
|
|
func (_UserService) retreiveUserDetail(uid string) (*model.UserDetail, error) {
|
|
if cachedUser, _ := cache.RetreiveEntity[model.UserDetail]("user_detail", uid); cachedUser != nil {
|
|
return cachedUser, nil
|
|
}
|
|
user := new(model.UserDetail)
|
|
has, err := global.DBConn.ID(uid).NoAutoCondition().Get(user)
|
|
if has {
|
|
cache.CacheEntity(*user, []string{fmt.Sprintf("user_%s", uid)}, "user_detail", uid)
|
|
}
|
|
return _postProcessSingle(user, has, err)
|
|
}
|
|
|
|
func (_UserService) findUserByID(uid string) (*model.User, error) {
|
|
cachedUser, _ := cache.RetreiveEntity[model.User]("user", uid)
|
|
if cachedUser != nil {
|
|
return cachedUser, nil
|
|
}
|
|
user := new(model.User)
|
|
has, err := global.DBConn.ID(uid).NoAutoCondition().Get(user)
|
|
if has {
|
|
cache.CacheEntity(*user, []string{fmt.Sprintf("user_%s", uid)}, "user", uid)
|
|
}
|
|
return _postProcessSingle(user, has, err)
|
|
}
|
|
|
|
func (_UserService) ListUserDetail(keyword string, userType int, userState *bool, page int) ([]model.JoinedUserDetail, int64, error) {
|
|
var (
|
|
cond = builder.NewCond()
|
|
cacheConditions = make([]string, 0)
|
|
)
|
|
cacheConditions = append(cacheConditions, strconv.Itoa(page))
|
|
cond = cond.And(builder.Neq{"d.id": "000"})
|
|
if len(keyword) != 0 {
|
|
keywordCond := builder.NewCond().
|
|
Or(builder.Like{"u.username", keyword}).
|
|
Or(builder.Like{"d.name", keyword})
|
|
cond = cond.And(keywordCond)
|
|
cacheConditions = append(cacheConditions, keyword)
|
|
}
|
|
if userType != -1 {
|
|
cond = cond.And(builder.Eq{"u.type": userType})
|
|
cacheConditions = append(cacheConditions, strconv.Itoa(userType))
|
|
}
|
|
if userState != nil {
|
|
cond = cond.And(builder.Eq{"u.enabled": *userState})
|
|
cacheConditions = append(cacheConditions, strconv.FormatBool(*userState))
|
|
}
|
|
startItem := (page - 1) * config.ServiceSettings.ItemsPageSize
|
|
var (
|
|
total int64
|
|
err error
|
|
)
|
|
if cacheCounts, err := cache.RetreiveCount("join_user_detail", cacheConditions...); cacheCounts != -1 && err == nil {
|
|
total = cacheCounts
|
|
} else {
|
|
total, err = global.DBConn.
|
|
Table("user_detail").Alias("d").
|
|
Join("INNER", []string{"user", "u"}, "d.id=u.id").
|
|
Where(cond).
|
|
Count(&model.User{})
|
|
if err != nil {
|
|
return nil, -1, err
|
|
}
|
|
cache.CacheCount([]string{"user"}, "join_user_detail", total, cacheConditions...)
|
|
}
|
|
users := make([]model.JoinedUserDetail, 0)
|
|
if cachedUsers, _ := cache.RetreiveSearch[[]model.JoinedUserDetail]("join_user_detail", cacheConditions...); cachedUsers != nil {
|
|
return *cachedUsers, total, nil
|
|
}
|
|
err = global.DBConn.
|
|
Table("user_detail").Alias("d").
|
|
Join("INNER", []string{"user", "u"}, "d.id=u.id").
|
|
Where(cond).
|
|
Limit(config.ServiceSettings.ItemsPageSize, startItem).
|
|
Find(&users)
|
|
cache.CacheSearch(users, []string{"user"}, "join_user_detail", cacheConditions...)
|
|
return users, total, err
|
|
}
|
|
|
|
func (_UserService) FetchUserDetail(uid string) (*model.FullJoinedUserDetail, error) {
|
|
if cachedUser, _ := cache.RetreiveEntity[model.FullJoinedUserDetail]("full_join_user_detail", uid); cachedUser != nil {
|
|
return cachedUser, nil
|
|
}
|
|
user := &model.FullJoinedUserDetail{}
|
|
has, err := global.DBConn.
|
|
Table("user_detail").Alias("d").
|
|
Join("INNER", []string{"user", "u"}, "d.id=u.id").
|
|
Where(builder.Eq{"d.id": uid}).
|
|
NoAutoCondition().
|
|
Get(user)
|
|
if has {
|
|
cache.CacheEntity(*user, []string{fmt.Sprintf("user_%s", uid)}, "full_join_user_detail", uid)
|
|
return user, nil
|
|
}
|
|
return nil, err
|
|
}
|