forked from free-lancers/electricity_bill_calc_service
		
	enhance(user):基本完成用户系列的Repository功能迁移。
This commit is contained in:
		| @@ -55,6 +55,15 @@ func (m ManagementAccountCreationForm) IntoUserDetail() *UserDetail { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | type UserModificationForm struct { | ||||||
|  | 	Name           string | ||||||
|  | 	Region         *string | ||||||
|  | 	Address        *string | ||||||
|  | 	Contact        *string | ||||||
|  | 	Phone          *string | ||||||
|  | 	UnitServiceFee *decimal.Decimal | ||||||
|  | } | ||||||
|  |  | ||||||
| type User struct { | type User struct { | ||||||
| 	Id          string | 	Id          string | ||||||
| 	Username    string | 	Username    string | ||||||
|   | |||||||
| @@ -9,9 +9,12 @@ import ( | |||||||
| 	"electricity_bill_calc/tools" | 	"electricity_bill_calc/tools" | ||||||
| 	"electricity_bill_calc/tools/time" | 	"electricity_bill_calc/tools/time" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"strings" | ||||||
|  | 	stdTime "time" | ||||||
|  |  | ||||||
| 	"github.com/doug-martin/goqu/v9" | 	"github.com/doug-martin/goqu/v9" | ||||||
| 	_ "github.com/doug-martin/goqu/v9/dialect/postgres" | 	_ "github.com/doug-martin/goqu/v9/dialect/postgres" | ||||||
|  | 	"github.com/fufuok/utils" | ||||||
| 	"github.com/georgysavva/scany/v2/pgxscan" | 	"github.com/georgysavva/scany/v2/pgxscan" | ||||||
| 	"go.uber.org/zap" | 	"go.uber.org/zap" | ||||||
| ) | ) | ||||||
| @@ -223,9 +226,9 @@ func (ur _UserRepository) CreateUser(user model.User, detail model.UserDetail, o | |||||||
| } | } | ||||||
|  |  | ||||||
| // 根据给定的条件检索用户 | // 根据给定的条件检索用户 | ||||||
| func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool, page uint) (*[]model.UserWithDetail, int64, error) { | func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool, page uint) ([]model.UserWithDetail, int64, error) { | ||||||
| 	ur.log.Info("根据给定的条件检索用户。", zap.Uint("page", page), zap.Stringp("keyword", keyword), zap.Int16("user type", userType), zap.Boolp("state", state)) | 	ur.log.Info("根据给定的条件检索用户。", zap.Uint("page", page), zap.Stringp("keyword", keyword), zap.Int16("user type", userType), zap.Boolp("state", state)) | ||||||
| 	if users, total, err := cache.RetrievePagedSearch[[]model.UserWithDetail]("user_with_detail", []string{ | 	cacheConditions := []string{ | ||||||
| 		fmt.Sprintf("%d", page), | 		fmt.Sprintf("%d", page), | ||||||
| 		tools.CondFn( | 		tools.CondFn( | ||||||
| 			func(v int16) bool { | 			func(v int16) bool { | ||||||
| @@ -237,8 +240,9 @@ func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool, | |||||||
| 		), | 		), | ||||||
| 		tools.DefaultStrTo("%s", state, "UNDEF"), | 		tools.DefaultStrTo("%s", state, "UNDEF"), | ||||||
| 		tools.DefaultTo(keyword, ""), | 		tools.DefaultTo(keyword, ""), | ||||||
| 	}...); err == nil && users != nil && total != -1 { | 	} | ||||||
| 		return users, total, nil | 	if users, total, err := cache.RetrievePagedSearch[[]model.UserWithDetail]("user_with_detail", cacheConditions...); err == nil && users != nil && total != -1 { | ||||||
|  | 		return *users, total, nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	ctx, cancel := global.TimeoutContext() | 	ctx, cancel := global.TimeoutContext() | ||||||
| @@ -299,30 +303,197 @@ func (ur _UserRepository) FindUser(keyword *string, userType int16, state *bool, | |||||||
| 	countSql, countParams, _ := countQuery.Prepared(true).ToSQL() | 	countSql, countParams, _ := countQuery.Prepared(true).ToSQL() | ||||||
| 	if err := pgxscan.Select(ctx, global.DB, &userWithDetails, userSql, userParams...); err != nil { | 	if err := pgxscan.Select(ctx, global.DB, &userWithDetails, userSql, userParams...); err != nil { | ||||||
| 		ur.log.Error("从数据库查询用户列表失败。", zap.Error(err)) | 		ur.log.Error("从数据库查询用户列表失败。", zap.Error(err)) | ||||||
| 		return nil, 0, err | 		return make([]model.UserWithDetail, 0), 0, err | ||||||
| 	} | 	} | ||||||
| 	if err := pgxscan.Get(ctx, global.DB, &userCount, countSql, countParams...); err != nil { | 	if err := pgxscan.Get(ctx, global.DB, &userCount, countSql, countParams...); err != nil { | ||||||
| 		ur.log.Error("从数据库查询用户列表总数失败。", zap.Error(err)) | 		ur.log.Error("从数据库查询用户列表总数失败。", zap.Error(err)) | ||||||
| 		return nil, 0, err | 		return make([]model.UserWithDetail, 0), 0, err | ||||||
| 	} | 	} | ||||||
| 	cache.CachePagedSearch( | 	cache.CachePagedSearch( | ||||||
| 		userWithDetails, | 		userWithDetails, | ||||||
| 		userCount, | 		userCount, | ||||||
| 		[]string{"user"}, | 		[]string{"user"}, | ||||||
| 		"user_with_detail", | 		"user_with_detail", | ||||||
| 		[]string{ | 		cacheConditions..., | ||||||
| 			fmt.Sprintf("%d", page), |  | ||||||
| 			tools.CondFn( |  | ||||||
| 				func(v int16) bool { |  | ||||||
| 					return v != -1 |  | ||||||
| 				}, |  | ||||||
| 				userType, |  | ||||||
| 				fmt.Sprintf("%d", userType), |  | ||||||
| 				"UNDEF", |  | ||||||
| 			), |  | ||||||
| 			tools.DefaultStrTo("%s", state, "UNDEF"), |  | ||||||
| 			tools.DefaultTo(keyword, ""), |  | ||||||
| 		}..., |  | ||||||
| 	) | 	) | ||||||
| 	return &userWithDetails, userCount, nil | 	return userWithDetails, userCount, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 更新指定用户的详细信息 | ||||||
|  | func (ur _UserRepository) UpdateDetail(uid string, userDetail model.UserModificationForm, operator *string) (bool, error) { | ||||||
|  | 	ur.log.Info("更新指定用户的详细信息。", zap.String("user id", uid)) | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	userDetailUpdateQuery := ur.ds. | ||||||
|  | 		Update("user_detail"). | ||||||
|  | 		Set(goqu.Record{ | ||||||
|  | 			"name": userDetail.Name, "abbr": tools.PinyinAbbr(userDetail.Name), "region": userDetail.Region, | ||||||
|  | 			"address": userDetail.Address, "contact": userDetail.Contact, "phone": userDetail.Phone, | ||||||
|  | 			"last_modified_at": time.Now(), "last_modified_by": operator, | ||||||
|  | 		}). | ||||||
|  | 		Where(goqu.Ex{"id": uid}) | ||||||
|  |  | ||||||
|  | 	if userDetail.UnitServiceFee != nil { | ||||||
|  | 		userDetailUpdateQuery = userDetailUpdateQuery.Set(goqu.Record{"unit_service_fee": userDetail.UnitServiceFee}) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	userDetailSql, userDetailParams, _ := userDetailUpdateQuery. | ||||||
|  | 		Prepared(true).ToSQL() | ||||||
|  |  | ||||||
|  | 	if res, err := global.DB.Exec(ctx, userDetailSql, userDetailParams...); err != nil { | ||||||
|  | 		ur.log.Error("向数据库更新指定用户的详细信息失败。", zap.String("user id", uid), zap.Error(err)) | ||||||
|  | 		return false, err | ||||||
|  | 	} else { | ||||||
|  | 		cache.AbolishRelation(fmt.Sprintf("user:%s", uid)) | ||||||
|  | 		return res.RowsAffected() > 0, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 更新指定用户的登录凭据 | ||||||
|  | func (ur _UserRepository) UpdatePassword(uid, newCredential string, needReset bool) (bool, error) { | ||||||
|  | 	ur.log.Info("更新指定用户的登录凭据。", zap.String("user id", uid)) | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	userUpdateQuery := ur.ds. | ||||||
|  | 		Update("user"). | ||||||
|  | 		Set(goqu.Record{"password": utils.Sha512Hex(newCredential), "reset_needed": needReset}). | ||||||
|  | 		Where(goqu.Ex{"id": uid}) | ||||||
|  |  | ||||||
|  | 	userSql, userParams, _ := userUpdateQuery. | ||||||
|  | 		Prepared(true).ToSQL() | ||||||
|  |  | ||||||
|  | 	if res, err := global.DB.Exec(ctx, userSql, userParams...); err != nil { | ||||||
|  | 		ur.log.Error("向数据库更新指定用户的登录凭据失败。", zap.String("user id", uid), zap.Error(err)) | ||||||
|  | 		return false, err | ||||||
|  | 	} else { | ||||||
|  | 		cache.AbolishRelation(fmt.Sprintf("user:%s", uid)) | ||||||
|  | 		return res.RowsAffected() > 0, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 更新指定用户的可用性状态 | ||||||
|  | func (ur _UserRepository) ChangeState(uid string, state bool) (bool, error) { | ||||||
|  | 	ur.log.Info("更新指定用户的可用性状态。", zap.String("user id", uid)) | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	userUpdateQuery := ur.ds. | ||||||
|  | 		Update("user"). | ||||||
|  | 		Set(goqu.Record{"enabled": state}). | ||||||
|  | 		Where(goqu.Ex{"id": uid}) | ||||||
|  |  | ||||||
|  | 	userSql, userParams, _ := userUpdateQuery. | ||||||
|  | 		Prepared(true).ToSQL() | ||||||
|  |  | ||||||
|  | 	if res, err := global.DB.Exec(ctx, userSql, userParams...); err != nil { | ||||||
|  | 		ur.log.Error("向数据库更新指定用户的可用性状态失败。", zap.String("user id", uid), zap.Error(err)) | ||||||
|  | 		return false, err | ||||||
|  | 	} else { | ||||||
|  | 		cache.AbolishRelation(fmt.Sprintf("user:%s", uid)) | ||||||
|  | 		return res.RowsAffected() > 0, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 检索条目数量有限的用户详细信息 | ||||||
|  | func (ur _UserRepository) SearchUsersWithLimit(userType *int16, keyword *string, limit uint) (*[]model.UserDetail, error) { | ||||||
|  | 	ur.log.Info("检索条目数量有限的用户详细信息。", zap.Int16p("user type", userType), zap.Uint("limit", limit), zap.Stringp("keyword", keyword)) | ||||||
|  | 	actualUserType := tools.DefaultTo(userType, model.USER_TYPE_ENT) | ||||||
|  | 	cacheConditions := []string{ | ||||||
|  | 		fmt.Sprintf("%d", actualUserType), | ||||||
|  | 		tools.DefaultTo(keyword, ""), | ||||||
|  | 		fmt.Sprintf("%d", limit), | ||||||
|  | 	} | ||||||
|  | 	if users, err := cache.RetrieveSearch[[]model.UserDetail]("user_with_detail_limited", cacheConditions...); err == nil && users != nil { | ||||||
|  | 		return users, nil | ||||||
|  | 	} | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	var users []model.UserDetail | ||||||
|  | 	userQuery := ur.ds. | ||||||
|  | 		From(goqu.T("user").As("u")). | ||||||
|  | 		Join(goqu.T("user_detail").As("ud"), goqu.On(goqu.Ex{"ud.id": goqu.I("u.id")})). | ||||||
|  | 		Select( | ||||||
|  | 			"u.id", "u.username", "u.reset_needed", "u.type", "u.enabled", | ||||||
|  | 			"ud.name", "ud.abbr", "ud.region", "ud.address", "ud.contact", "ud.phone", | ||||||
|  | 			"ud.unit_service_fee", "ud.service_expiration", | ||||||
|  | 			"ud.created_at", "ud.created_by", "ud.last_modified_at", "ud.last_modified_by", | ||||||
|  | 		) | ||||||
|  |  | ||||||
|  | 	if keyword != nil && len(*keyword) > 0 { | ||||||
|  | 		pattern := fmt.Sprintf("%%%s%%", *keyword) | ||||||
|  | 		userQuery = userQuery.Where( | ||||||
|  | 			goqu.Or( | ||||||
|  | 				goqu.Ex{"u.username": goqu.Op{"like": pattern}}, | ||||||
|  | 				goqu.Ex{"ud.name": goqu.Op{"like": pattern}}, | ||||||
|  | 				goqu.Ex{"ud.abbr": goqu.Op{"like": pattern}}, | ||||||
|  | 			), | ||||||
|  | 		) | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	userQuery = userQuery.Where(goqu.Ex{"u.type": actualUserType}) | ||||||
|  |  | ||||||
|  | 	userQuery.Order(goqu.I("u.created_at").Desc()).Limit(limit) | ||||||
|  |  | ||||||
|  | 	userSql, userParams, _ := userQuery.Prepared(true).ToSQL() | ||||||
|  | 	if err := pgxscan.Select(ctx, global.DB, &users, userSql, userParams...); err != nil { | ||||||
|  | 		ur.log.Error("从数据库查询用户列表失败。", zap.Error(err)) | ||||||
|  | 		return nil, err | ||||||
|  | 	} | ||||||
|  | 	cache.CacheSearch(users, []string{"user"}, "user_with_detail_limited", cacheConditions...) | ||||||
|  | 	return &users, nil | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 更新指定用户的服务有效期限 | ||||||
|  | func (ur _UserRepository) UpdateServiceExpiration(uid string, expiration stdTime.Time) (bool, error) { | ||||||
|  | 	ur.log.Info("更新指定用户的服务有效期限。", zap.String("user id", uid)) | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	userDetailUpdateQuery := ur.ds. | ||||||
|  | 		Update("user_detail"). | ||||||
|  | 		Set(goqu.Record{"service_expiration": expiration}). | ||||||
|  | 		Where(goqu.Ex{"id": uid}) | ||||||
|  |  | ||||||
|  | 	userDetailSql, userDetailParams, _ := userDetailUpdateQuery. | ||||||
|  | 		Prepared(true).ToSQL() | ||||||
|  |  | ||||||
|  | 	if res, err := global.DB.Exec(ctx, userDetailSql, userDetailParams...); err != nil { | ||||||
|  | 		ur.log.Error("向数据库更新指定用户的服务有效期限失败。", zap.String("user id", uid), zap.Error(err)) | ||||||
|  | 		return false, err | ||||||
|  | 	} else { | ||||||
|  | 		cache.AbolishRelation(fmt.Sprintf("user:%s", uid)) | ||||||
|  | 		return res.RowsAffected() > 0, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // 检索指定用户列表的详细信息 | ||||||
|  | func (ur _UserRepository) RetrieveUsersDetail(uids []string) ([]model.UserDetail, error) { | ||||||
|  | 	ur.log.Info("检索指定用户列表的详细信息。", zap.Strings("user ids", uids)) | ||||||
|  | 	if len(uids) == 0 { | ||||||
|  | 		return make([]model.UserDetail, 0), nil | ||||||
|  | 	} | ||||||
|  | 	cacheConditions := []string{ | ||||||
|  | 		strings.Join(uids, ","), | ||||||
|  | 	} | ||||||
|  | 	if users, err := cache.RetrieveSearch[[]model.UserDetail]("user_detail", cacheConditions...); err == nil && users != nil { | ||||||
|  | 		return *users, nil | ||||||
|  | 	} | ||||||
|  | 	ctx, cancel := global.TimeoutContext() | ||||||
|  | 	defer cancel() | ||||||
|  |  | ||||||
|  | 	var users []model.UserDetail | ||||||
|  | 	userQuery := ur.ds. | ||||||
|  | 		From("user_detail"). | ||||||
|  | 		Where(goqu.Ex{"id": goqu.Any(uids)}) | ||||||
|  |  | ||||||
|  | 	userSql, userParams, _ := userQuery.Prepared(true).ToSQL() | ||||||
|  | 	if err := pgxscan.Select(ctx, global.DB, &users, userSql, userParams...); err != nil { | ||||||
|  | 		ur.log.Error("从数据库查询用户列表失败。", zap.Error(err)) | ||||||
|  | 		return make([]model.UserDetail, 0), err | ||||||
|  | 	} | ||||||
|  | 	cache.CacheSearch(users, []string{"user", "user_detail"}, "user", cacheConditions...) | ||||||
|  | 	return users, nil | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user