package mysql import ( "context" "errors" "strings" "gorm.io/gorm" "gorm.io/gorm/clause" "wucher/internal/domain/auth" ) type RoleRepository struct { db *gorm.DB } func NewRoleRepository(db *gorm.DB) *RoleRepository { return &RoleRepository{db: db} } func (r *RoleRepository) CreateRole(ctx context.Context, role *auth.Role) error { if actor := actorUserIDFromContext(ctx); len(actor) > 0 { role.CreatedBy = actor role.UpdatedBy = actor } return r.db.WithContext(ctx).Create(role).Error } func (r *RoleRepository) UpdateRole(ctx context.Context, role *auth.Role) error { if actor := actorUserIDFromContext(ctx); len(actor) > 0 { role.UpdatedBy = actor } return r.db.WithContext(ctx).Save(role).Error } func (r *RoleRepository) DeleteRole(ctx context.Context, id []byte) error { return r.db.WithContext(ctx).Delete(&auth.Role{}, "id = ?", id).Error } func (r *RoleRepository) GetRoleByID(ctx context.Context, id []byte) (*auth.Role, error) { var role auth.Role err := r.db.WithContext(ctx).First(&role, "id = ?", id).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &role, err } func (r *RoleRepository) GetRoleByName(ctx context.Context, name string) (*auth.Role, error) { var role auth.Role err := r.db.WithContext(ctx).Where("name = ?", name).First(&role).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &role, err } func (r *RoleRepository) HasRolePermission(ctx context.Context, roleID []byte, permissionKey string) (bool, error) { var count int64 err := r.db.WithContext(ctx). Table("role_permissions rp"). Joins("JOIN permissions p ON p.id = rp.permission_id"). Where("rp.role_id = ? AND p.`key` = ?", roleID, permissionKey). Count(&count).Error if err != nil { return false, err } return count > 0, nil } func (r *RoleRepository) GetPermissionByID(ctx context.Context, id []byte) (*auth.Permission, error) { var perm auth.Permission err := r.db.WithContext(ctx).First(&perm, "id = ?", id).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &perm, err } func (r *RoleRepository) GetPermissionByKey(ctx context.Context, key string) (*auth.Permission, error) { var perm auth.Permission err := r.db.WithContext(ctx).Where("`key` = ?", strings.ToLower(strings.TrimSpace(key))).First(&perm).Error if errors.Is(err, gorm.ErrRecordNotFound) { return nil, nil } return &perm, err } func (r *RoleRepository) UpdatePermission(ctx context.Context, permission *auth.Permission) error { if actor := actorUserIDFromContext(ctx); len(actor) > 0 { permission.UpdatedBy = actor } return r.db.WithContext(ctx).Save(permission).Error } func (r *RoleRepository) ListPermissionsByRoleID(ctx context.Context, roleID []byte) ([]auth.Permission, error) { var perms []auth.Permission err := r.db.WithContext(ctx). Table("permissions p"). Select("p.*"). Joins("JOIN role_permissions rp ON rp.permission_id = p.id"). Where("rp.role_id = ?", roleID). Order("p.name ASC"). Find(&perms).Error if err != nil { return nil, err } return perms, nil } func (r *RoleRepository) AssignPermission(ctx context.Context, roleID, permissionID []byte) (*auth.RolePermission, error) { rp := &auth.RolePermission{RoleID: roleID, PermissionID: permissionID} if actor := actorUserIDFromContext(ctx); len(actor) > 0 { rp.CreatedBy = actor rp.UpdatedBy = actor } err := r.db.WithContext(ctx). Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "role_id"}, {Name: "permission_id"}}, DoNothing: true, }). Create(rp).Error if err != nil { return nil, err } // Already exists, return current row. if len(rp.ID) == 0 { var existing auth.RolePermission if err := r.db.WithContext(ctx). Where("role_id = ? AND permission_id = ?", roleID, permissionID). First(&existing).Error; err != nil { return nil, err } return &existing, nil } return rp, nil } func (r *RoleRepository) RemovePermission(ctx context.Context, roleID, permissionID []byte) error { return r.db.WithContext(ctx). Delete(&auth.RolePermission{}, "role_id = ? AND permission_id = ?", roleID, permissionID). Error } func (r *RoleRepository) ListPermissions(ctx context.Context, filter string, sort string, limit, offset int) ([]auth.Permission, int64, error) { var perms []auth.Permission var total int64 query := r.db.WithContext(ctx).Model(&auth.Permission{}) if filter != "" { like := "%" + strings.ToLower(filter) + "%" query = query.Where("LOWER(name) LIKE ? OR LOWER(`key`) LIKE ?", like, like) } if err := query.Count(&total).Error; err != nil { return nil, 0, err } if sort != "" { query = query.Order(sort) } else { query = query.Order("created_at DESC") } if limit > 0 { query = query.Limit(limit).Offset(offset) } if err := query.Find(&perms).Error; err != nil { return nil, 0, err } return perms, total, nil } func (r *RoleRepository) ListRoles(ctx context.Context, filterName, sort string, limit, offset int) ([]auth.Role, int64, error) { var roles []auth.Role var total int64 query := r.db.WithContext(ctx).Model(&auth.Role{}) if filterName != "" { query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(filterName)+"%") } if err := query.Count(&total).Error; err != nil { return nil, 0, err } if sort != "" { query = query.Order(sort) } else { query = query.Order("created_at DESC") } if limit > 0 { query = query.Limit(limit).Offset(offset) } if err := query.Find(&roles).Error; err != nil { return nil, 0, err } return roles, total, nil }