app-cloudep-member-server/pkg/repository/user.go

369 lines
9.1 KiB
Go
Raw Normal View History

2024-12-30 03:58:14 +00:00
package repository
import (
"app-cloudep-member-server/pkg/domain"
"app-cloudep-member-server/pkg/domain/entity"
"app-cloudep-member-server/pkg/domain/repository"
"context"
"errors"
"fmt"
mgo "code.30cm.net/digimon/library-go/mongo"
"time"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/mon"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type UserRepositoryParam struct {
Conf *mgo.Conf
CacheConf cache.CacheConf
DbOpts []mon.Option
CacheOpts []cache.Option
}
type UserRepository struct {
DB mgo.DocumentDBWithCacheUseCase
}
func NewUserRepository(param UserRepositoryParam) repository.UserRepository {
e := entity.User{}
documentDB, err := mgo.MustDocumentDBWithCache(
param.Conf,
e.CollectionName(),
param.CacheConf,
param.DbOpts,
param.CacheOpts,
)
if err != nil {
panic(err)
}
return &UserRepository{
DB: documentDB,
}
}
func (repo *UserRepository) Insert(ctx context.Context, data *entity.User) error {
if data.ID.IsZero() {
now := time.Now().UTC().UnixNano()
data.ID = primitive.NewObjectID()
data.CreateAt = &now
data.UpdateAt = &now
}
rk := domain.GetUserRedisKey(data.ID.Hex())
_, err := repo.DB.InsertOne(ctx, rk, data)
return err
}
func (repo *UserRepository) FindOne(ctx context.Context, id string) (*entity.User, error) {
oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
return nil, ErrInvalidObjectID
}
var data entity.User
rk := domain.GetUserRedisKey(id)
err = repo.DB.FindOne(ctx, rk, &data, bson.M{"_id": oid})
switch {
case err == nil:
return &data, nil
case errors.Is(err, mon.ErrNotFound):
return nil, ErrNotFound
default:
return nil, err
}
}
func (repo *UserRepository) Update(ctx context.Context, data *entity.User) (*mongo.UpdateResult, error) {
now := time.Now().UTC().UnixNano()
data.UpdateAt = &now
rk := domain.GetUserRedisKey(data.ID.Hex())
res, err := repo.DB.UpdateOne(ctx, rk, bson.M{"_id": data.ID}, bson.M{"$set": data})
return res, err
}
func (repo *UserRepository) Delete(ctx context.Context, id string) (int64, error) {
oid, err := primitive.ObjectIDFromHex(id)
if err != nil {
return 0, ErrInvalidObjectID
}
rk := domain.GetUserRedisKey(id)
res, err := repo.DB.DeleteOne(ctx, rk, bson.M{"_id": oid})
return res, err
}
func (repo *UserRepository) UpdateUserDetailsByUID(ctx context.Context, data *repository.UpdateUserInfoRequest) error {
updateFields := bson.M{}
if data.AlarmCategory != nil {
updateFields["alarm_category"] = *data.AlarmCategory
}
if data.UserStatus != nil {
updateFields["user_status"] = *data.UserStatus
}
if data.PreferredLanguage != nil {
updateFields["preferred_language"] = *data.PreferredLanguage
}
if data.Currency != nil {
updateFields["currency"] = *data.Currency
}
if data.Nickname != nil {
updateFields["nickname"] = *data.Nickname
}
if data.AvatarURL != nil {
updateFields["avatar_url"] = *data.AvatarURL
}
if data.FullName != nil {
updateFields["full_name"] = *data.FullName
}
if data.GenderCode != nil {
updateFields["gender_code"] = *data.GenderCode
}
if data.Birthdate != nil {
updateFields["birthdate"] = *data.Birthdate
}
if data.Address != nil {
updateFields["address"] = *data.Address
}
if len(updateFields) == 0 {
return nil
}
updateFields["update_at"] = time.Now().UTC().UnixNano()
filter := bson.M{"uid": data.UID}
update := bson.M{"$set": updateFields}
// 不常寫,再找一次可接受
id := repo.UIDToID(ctx, data.UID)
if id == "" {
return errors.New("invalid uid")
}
rk := domain.GetUserRedisKey(id)
result, err := repo.DB.UpdateOne(ctx, rk, filter, update, options.Update().SetUpsert(false))
if err != nil {
return err
}
if result.MatchedCount == 0 {
return ErrNotFound // 自定義的錯誤表示未找到記錄
}
return nil
}
func (repo *UserRepository) UpdateStatus(ctx context.Context, uid string, status int32) error {
filter := bson.M{"uid": uid}
// 構建更新內容,僅更新 status 字段並記錄 update_at 時間
update := bson.M{
"$set": bson.M{
"user_status": status,
"update_at": time.Now().UTC().UnixNano(),
},
}
// 不常寫,再找一次可接受
id := repo.UIDToID(ctx, uid)
if id == "" {
return errors.New("invalid uid")
}
rk := domain.GetUserRedisKey(id)
// 執行更新操作
result, err := repo.DB.UpdateOne(ctx, rk, filter, update, options.Update().SetUpsert(false))
if err != nil {
return fmt.Errorf("failed to update status for uid %s: %w", uid, err)
}
// 檢查更新結果,若沒有匹配的文檔,則返回錯誤
if result.MatchedCount == 0 {
return ErrNotFound // 自定義的錯誤表示未找到記錄
}
return nil
}
func (repo *UserRepository) FindOneByUID(ctx context.Context, uid string) (*entity.User, error) {
// 構建查找條件
filter := bson.M{"uid": uid}
var data entity.User
// 不常寫,再找一次可接受
id := repo.UIDToID(ctx, uid)
if id == "" {
return nil, errors.New("invalid uid")
}
rk := domain.GetUserRedisKey(id)
err := repo.DB.FindOne(ctx, rk, &data, filter)
switch {
case err == nil:
return &data, nil
case errors.Is(err, mon.ErrNotFound):
return nil, ErrNotFound
default:
return nil, err
}
}
func (repo *UserRepository) FindOneByNickName(ctx context.Context, nickName string) (*entity.User, error) {
// 構建查找條件
filter := bson.M{"nickname": nickName}
var data entity.User
err := repo.DB.GetClient().FindOne(ctx, &data, filter)
switch {
case err == nil:
return &data, nil
case errors.Is(err, mon.ErrNotFound):
return nil, ErrNotFound
default:
return nil, err
}
}
func (repo *UserRepository) ListMembers(ctx context.Context, params *repository.UserQueryParams) ([]*entity.User, int64, error) {
// 構建查詢條件
filter := bson.M{}
if params.AlarmCategory != nil {
filter["alarm_category"] = *params.AlarmCategory
}
if params.UserStatus != nil {
filter["user_status"] = *params.UserStatus
}
if params.CreateStartTime != nil || params.CreateEndTime != nil {
timeFilter := bson.M{}
if params.CreateStartTime != nil {
timeFilter["$gte"] = *params.CreateStartTime
}
if params.CreateEndTime != nil {
timeFilter["$lte"] = *params.CreateEndTime
}
filter["create_at"] = timeFilter
}
// 計算符合條件的總數
count, err := repo.DB.GetClient().CountDocuments(ctx, filter)
if err != nil {
return nil, 0, err
}
// 構建查詢選項(分頁)
opts := options.Find().
SetSkip(params.PageSize * (params.PageIndex - 1)).
SetLimit(params.PageSize)
// 執行查詢
var users = make([]*entity.User, 0, params.PageSize)
err = repo.DB.GetClient().Find(ctx, &users, filter, opts)
if err != nil {
return nil, 0, err
}
return users, count, nil
}
func (repo *UserRepository) UpdateEmailVerifyStatus(ctx context.Context, uid, email string) error {
// 構建查找條件
filter := bson.M{"uid": uid}
// 構建更新內容,僅更新 status 字段並記錄 update_at 時間
update := bson.M{
"$set": bson.M{
"email": email,
"update_at": time.Now().UTC().UnixNano(),
},
}
// 不常寫,再找一次可接受
id := repo.UIDToID(ctx, uid)
if id == "" {
return errors.New("invalid uid")
}
rk := domain.GetUserRedisKey(id)
// 執行更新操作
result, err := repo.DB.UpdateOne(ctx, rk, filter, update, options.Update().SetUpsert(false))
if err != nil {
return fmt.Errorf("failed to update status for uid %s: %w", uid, err)
}
// 檢查更新結果,若沒有匹配的文檔,則返回錯誤
if result.MatchedCount == 0 {
return ErrNotFound // 自定義的錯誤表示未找到記錄
}
return nil
}
func (repo *UserRepository) UpdatePhoneVerifyStatus(ctx context.Context, uid, phone string) error {
// 構建查找條件
filter := bson.M{"uid": uid}
// 構建更新內容,僅更新 status 字段並記錄 update_at 時間
update := bson.M{
"$set": bson.M{
"phone_number": phone,
"update_at": time.Now().UTC().UnixNano(),
},
}
// 不常寫,再找一次可接受
id := repo.UIDToID(ctx, uid)
if id == "" {
return errors.New("invalid uid")
}
rk := domain.GetUserRedisKey(id)
// 執行更新操作
result, err := repo.DB.UpdateOne(ctx, rk, filter, update, options.Update().SetUpsert(false))
if err != nil {
return fmt.Errorf("failed to update status for uid %s: %w", uid, err)
}
// 檢查更新結果,若沒有匹配的文檔,則返回錯誤
if result.MatchedCount == 0 {
return ErrNotFound // 自定義的錯誤表示未找到記錄
}
return nil
}
func (repo *UserRepository) UIDToID(ctx context.Context, uid string) string {
filter := bson.M{"uid": uid}
var user entity.User
opts := options.FindOne().SetProjection(bson.M{
"_id": 1,
})
err := repo.DB.GetClient().FindOne(ctx, &user, filter, opts)
if err != nil {
return ""
}
return user.ID.Hex()
}
func (repo *UserRepository) Index20241226001UP(ctx context.Context) (*mongo.Cursor, error) {
// db.user_info.createIndex({"uid": 1},{unique: true})
repo.DB.PopulateIndex(ctx, "uid", 1, true)
// db.user_info.createIndex({"create_at": 1})
repo.DB.PopulateIndex(ctx, "create_at", 1, false)
return repo.DB.GetClient().Indexes().List(ctx)
}