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 RoleRepositoryParam struct { Conf *mongo.Conf CacheConf cache.CacheConf DBOpts []mon.Option CacheOpts []cache.Option } type RoleRepository struct { DB mongo.DocumentDBWithCacheUseCase } // NewRoleRepository 創建角色倉庫實例 func NewRoleRepository(param RoleRepositoryParam) repository.RoleRepository { e := entity.Role{} documentDB, err := mongo.MustDocumentDBWithCache( param.Conf, e.CollectionName(), param.CacheConf, param.DBOpts, param.CacheOpts, ) if err != nil { panic(err) } return &RoleRepository{ DB: documentDB, } } func (repo *RoleRepository) Create(ctx context.Context, role *entity.Role) error { now := time.Now() role.CreateTime = now role.UpdateTime = now id := bson.NewObjectID() role.ID = id rk := domain.GetRoleRedisKeyRedisKey(id.Hex()) _, err := repo.DB.InsertOne(ctx, rk, role) if err != nil { // 檢查是否為重複鍵錯誤 if mongodriver.IsDuplicateKeyError(err) { return errs.ResourceAlreadyExist(role.ClientID) } return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } func (repo *RoleRepository) GetByID(ctx context.Context, id string) (*entity.Role, error) { var role entity.Role objID, err := bson.ObjectIDFromHex(id) if err != nil { return nil, err } rk := domain.GetRoleRedisKeyRedisKey(id) err = repo.DB.FindOne(ctx, rk, &role, bson.M{"client_id": objID}) if err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, errs.ResourceNotFoundWithScope( code.CloudEPPermission, domain.FailedToGetRoleByID, "failed to get role by id") } return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return &role, nil } func (repo *RoleRepository) GetByUID(ctx context.Context, uid string) (*entity.Role, error) { var role entity.Role rk := domain.GetRoleRedisKeyRedisKey(uid) err := repo.DB.FindOne(ctx, rk, &role, bson.M{"uid": uid, "status": permission.StatusActive}) if err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, errs.ResourceNotFoundWithScope( code.CloudEPPermission, domain.FailedToGetByUID, "failed to get role by uid") } return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return &role, nil } func (repo *RoleRepository) GetByClientAndName(ctx context.Context, clientID, name string) (*entity.Role, error) { filter := bson.M{ "client_id": clientID, "name": name, "status": permission.StatusActive, } var role entity.Role err := repo.DB.GetClient().FindOne(ctx, &role, filter) if err != nil { if errors.Is(err, mongodriver.ErrNoDocuments) { return nil, errs.ResourceNotFoundWithScope( code.CloudEPPermission, domain.FailedToGetByClientAndName, "failed to get by client and name") } return nil, errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return &role, nil } func (repo *RoleRepository) Update(ctx context.Context, id string, role *entity.Role) error { role.UpdateTime = time.Now() objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } update := bson.M{ "$set": bson.M{ "name": role.Name, "status": role.Status, "permissions": role.Permissions, "update_time": role.UpdateTime, }, } rk := domain.GetRoleRedisKeyRedisKey(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 *RoleRepository) Delete(ctx context.Context, id string) error { rk := domain.GetRoleRedisKeyRedisKey(id) objID, err := bson.ObjectIDFromHex(id) if err != nil { return err } gc, err := repo.GetByID(ctx, id) if err != nil { return err } rk = domain.GetRoleRedisKeyRedisKey(gc.UID) err = repo.DB.DelCache(ctx, rk) if err != nil { return err } _, err = repo.DB.DeleteOne(ctx, rk, bson.M{"_id": objID}) if err != nil { return errs.DBErrorWithScope(code.CloudEPPermission, err.Error()) } return nil } func (repo *RoleRepository) List(ctx context.Context, filter repository.RoleFilter) ([]*entity.Role, error) { query := bson.M{} if filter.ClientID != "" { query["client_id"] = filter.ClientID } if filter.Status != nil { query["status"] = *filter.Status } var roles []*entity.Role err := repo.DB.GetClient().Find(ctx, &roles, 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 roles, nil } func (repo *RoleRepository) GetRolesByClientID(ctx context.Context, clientID string) ([]*entity.Role, error) { status := permission.StatusActive filter := repository.RoleFilter{ ClientID: clientID, Status: &status, } return repo.List(ctx, filter) } // Index20241226001UP 創建索引 func (repo *RoleRepository) Index20241226001UP(ctx context.Context) (*mongodriver.Cursor, error) { // 等價於 db.account.createIndex({ "login_id": 1, "platform": 1}, {unique: true}) repo.DB.PopulateMultiIndex(ctx, []string{ "client_id", "name", }, []int32{1, 1}, true) // 等價於 db.account.createIndex({"create_at": 1}) repo.DB.PopulateIndex(ctx, "uid", 1, true) repo.DB.PopulateIndex(ctx, "status", 1, false) return repo.DB.GetClient().Indexes().List(ctx) }