369 lines
9.1 KiB
Go
369 lines
9.1 KiB
Go
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)
|
|
}
|