package repository import ( "context" "errors" "time" "github.com/google/uuid" "github.com/jackc/pgx/v5" ) // AdminRole is an ops RBAC role. type AdminRole struct { ID uuid.UUID `json:"id"` Name string `json:"name"` System bool `json:"system"` CreatedAt time.Time `json:"created_at"` } // ListAdminRoles returns all roles. func (r *AdminRepo) ListAdminRoles(ctx context.Context) ([]AdminRole, error) { rows, err := r.Pool.Query(ctx, ` SELECT id, name, system, created_at FROM admin_roles ORDER BY name`) if err != nil { return nil, err } defer rows.Close() var out []AdminRole for rows.Next() { var a AdminRole if err := rows.Scan(&a.ID, &a.Name, &a.System, &a.CreatedAt); err != nil { return nil, err } out = append(out, a) } return out, rows.Err() } // GetAdminRole loads one role. func (r *AdminRepo) GetAdminRole(ctx context.Context, id uuid.UUID) (*AdminRole, error) { var a AdminRole err := r.Pool.QueryRow(ctx, ` SELECT id, name, system, created_at FROM admin_roles WHERE id=$1`, id, ).Scan(&a.ID, &a.Name, &a.System, &a.CreatedAt) if errors.Is(err, pgx.ErrNoRows) { return nil, nil } if err != nil { return nil, err } return &a, nil } // ListRolePermissions returns permission codes for a role. func (r *AdminRepo) ListRolePermissions(ctx context.Context, roleID uuid.UUID) ([]string, error) { rows, err := r.Pool.Query(ctx, ` SELECT code FROM admin_role_permissions WHERE role_id=$1 ORDER BY code`, roleID) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var c string if err := rows.Scan(&c); err != nil { return nil, err } out = append(out, c) } return out, rows.Err() } // ReplaceRolePermissions replaces the full permission set for a role. func (r *AdminRepo) ReplaceRolePermissions(ctx context.Context, roleID uuid.UUID, codes []string) error { tx, err := r.Pool.Begin(ctx) if err != nil { return err } defer tx.Rollback(ctx) if _, err := tx.Exec(ctx, `DELETE FROM admin_role_permissions WHERE role_id=$1`, roleID); err != nil { return err } for _, code := range codes { if _, err := tx.Exec(ctx, ` INSERT INTO admin_role_permissions(role_id, code) VALUES ($1,$2)`, roleID, code); err != nil { return err } } return tx.Commit(ctx) } // ListPermissionsForAdmin returns permission codes for an admin account. func (r *AdminRepo) ListPermissionsForAdmin(ctx context.Context, adminID uuid.UUID) ([]string, error) { rows, err := r.Pool.Query(ctx, ` SELECT p.code FROM admin_accounts a JOIN admin_role_permissions p ON p.role_id = a.role_id WHERE a.id=$1 AND a.deleted_at IS NULL AND a.role_id IS NOT NULL ORDER BY p.code`, adminID) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var c string if err := rows.Scan(&c); err != nil { return nil, err } out = append(out, c) } return out, rows.Err() } // GetAdminRoleMeta returns role id/name for an account. func (r *AdminRepo) GetAdminRoleMeta(ctx context.Context, adminID uuid.UUID) (roleID *uuid.UUID, name string, err error) { var id uuid.UUID err = r.Pool.QueryRow(ctx, ` SELECT r.id, r.name FROM admin_accounts a JOIN admin_roles r ON r.id = a.role_id WHERE a.id=$1 AND a.deleted_at IS NULL`, adminID, ).Scan(&id, &name) if errors.Is(err, pgx.ErrNoRows) { return nil, "", nil } if err != nil { return nil, "", err } return &id, name, nil }