package repository import ( "backend/pkg/library/errs/code" "backend/pkg/permission/domain" "backend/pkg/permission/domain/permission" "context" "errors" "go.mongodb.org/mongo-driver/v2/mongo/options" "time" "backend/pkg/library/errs" "backend/pkg/library/mongo" "backend/pkg/permission/domain/entity" "backend/pkg/permission/domain/repository" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/mon" "go.mongodb.org/mongo-driver/v2/bson" mongodriver "go.mongodb.org/mongo-driver/v2/mongo" ) type UserRoleRepositoryParam struct { Conf *mongo.Conf CacheConf cache.CacheConf DBOpts []mon.Option CacheOpts []cache.Option } type UserRoleRepository struct { DB mongo.DocumentDBWithCacheUseCase } // NewUserRoleRepository 創建用戶角色倉庫實例 func NewUserRoleRepository(param UserRoleRepositoryParam) repository.UserRoleRepository { e := entity.UserRole{} documentDB, err := mongo.MustDocumentDBWithCache( param.Conf, e.CollectionName(), param.CacheConf, param.DBOpts, param.CacheOpts, ) if err != nil { panic(err) } return &UserRoleRepository{ DB: documentDB, } } func (repo *UserRoleRepository) Create(ctx context.Context, userRole *entity.UserRole) error { now := time.Now() userRole.CreateTime = now userRole.UpdateTime = now id := bson.NewObjectID() userRole.ID = id rk := domain.GetUserRoleRedisKey(id.Hex()) userRole.CreateTime = time.Now() userRole.UpdateTime = time.Now() _, err := repo.DB.InsertOne(ctx, rk, userRole) if err != nil { // 檢查是否為重複鍵錯誤 if mongodriver.IsDuplicateKeyError(err) { return errs.ResourceAlreadyExist("failed to insert user role") } return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } func (repo *UserRoleRepository) GetByID(ctx context.Context, id string) (*entity.UserRole, error) { var userRole entity.UserRole objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } rk := domain.GetUserRoleRedisKey(id) err = repo.DB.FindOne(ctx, rk, &userRole, bson.M{"_id": objID}) if err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, errs.ResourceNotFoundWithScope( code.CloudEPPermission, domain.FailedToGetRoleByID, "failed to get user role by id") } return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return &userRole, nil } func (repo *UserRoleRepository) GetByUserAndRole(ctx context.Context, uid, roleUID string) (*entity.UserRole, error) { filter := bson.M{ "uid": uid, "role_uid": roleUID, "status": permission.StatusActive, } var userRole entity.UserRole err := repo.DB.GetClient().Find(ctx, &userRole, filter) if err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, errs.ResourceNotFoundWithScope(code.CloudEPPermission, 0, "failed to get user and role") } return nil, errs.DatabaseErrorWithScope(code.CloudEPPermission, 0, err.Error()) } return &userRole, nil } func (repo *UserRoleRepository) Update(ctx context.Context, id string, userRole *entity.UserRole) error { userRole.UpdateTime = time.Now() objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } update := bson.M{ "$set": bson.M{ "status": userRole.Status, "update_time": userRole.UpdateTime, }, } rk := domain.GetUserRoleRedisKey(id) _, err = repo.DB.UpdateOne(ctx, rk, bson.M{"_id": objID}, update) if err != nil { return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } func (repo *UserRoleRepository) Delete(ctx context.Context, id string) error { objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } rk := domain.GetUserRoleRedisKey(id) _, err = repo.DB.DeleteOne(ctx, rk, bson.M{"_id": objID}) if err != nil { return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } func (repo *UserRoleRepository) List(ctx context.Context, filter repository.UserRoleFilter) ([]*entity.UserRole, error) { query := bson.M{} if filter.Brand != "" { query["brand"] = filter.Brand } if filter.UID != "" { query["uid"] = filter.UID } if filter.RoleUID != "" { query["role_uid"] = filter.RoleUID } if filter.Status != nil { query["status"] = *filter.Status } var userRoles []*entity.UserRole err := repo.DB.GetClient().Find(ctx, &userRoles, query) if err != nil { return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } err = repo.DB.GetClient().Find(ctx, &userRoles, query, options.Find().SetLimit(int64(filter.Limit)), options.Find().SetSkip(int64(filter.Skip))) if err != nil { return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return userRoles, nil } func (repo *UserRoleRepository) GetUserRolesByUID(ctx context.Context, uid string) ([]*entity.UserRole, error) { status := permission.StatusActive filter := repository.UserRoleFilter{ UID: uid, Status: &status, } return repo.List(ctx, filter) } func (repo *UserRoleRepository) DeleteByUserAndRole(ctx context.Context, uid, roleUID string) error { filter := repository.UserRoleFilter{ UID: uid, RoleUID: roleUID, } list, err := repo.List(ctx, filter) if err != nil { return err } if len(list) == 0 { return nil } for _, item := range list { _ = repo.DB.DelCache(ctx, domain.GetUserRoleRedisKey(item.ID.Hex())) } _, err = repo.DB.GetClient().DeleteMany(ctx, filter) if err != nil { return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } // Index20241226001UP 創建索引 func (repo *UserRoleRepository) Index20241226001UP(ctx context.Context) (*mongodriver.Cursor, error) { // 等價於 db.account.createIndex({ "login_id": 1, "platform": 1}, {unique: true}) repo.DB.PopulateMultiIndex(ctx, []string{ "uid", "role_uid", }, []int32{1, 1}, true) // 等價於 db.account.createIndex({"create_at": 1}) repo.DB.PopulateIndex(ctx, "uid", 1, false) repo.DB.PopulateIndex(ctx, "status", 1, false) return repo.DB.GetClient().Indexes().List(ctx) }