1
0
forked from baron/baron-sso
Files
baron-sso/backend/internal/repository/client_consent_repository.go
chan 31d107ff2e feat(user): support fixed UUID registration and enhance bulk import results
- Added support for fixed UUIDs during bulk registration (Search-first + ExternalID mapping)
- Implemented idempotency and visibility restoration for soft-deleted users
- Enhanced bulk upload UI to show 'New/Updated/Unchanged' status and modified fields
- Added logic to reclaim identifiers (login_id) from colliding records
- Added frontend E2E and backend unit tests for UUID integrity and conflict handling
- Fixed i18n, formatting, and mock tests to satisfy code-check
- Applied 'go fix' for 'omitzero' tags and general Go standards
2026-06-01 15:34:08 +09:00

139 lines
4.8 KiB
Go

package repository
import (
"baron-sso-backend/internal/domain"
"context"
"errors"
"gorm.io/gorm"
)
type ClientConsentRepository interface {
Upsert(ctx context.Context, consent *domain.ClientConsent) error
Delete(ctx context.Context, subject, clientID string) error
DeleteByClient(ctx context.Context, clientID string) error
List(ctx context.Context, clientID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error)
ListByTenant(ctx context.Context, clientID, tenantID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error)
ListBySubject(ctx context.Context, subject string) ([]domain.ClientConsent, error)
ListSubjectsByClient(ctx context.Context, clientID string) ([]string, error)
Find(ctx context.Context, clientID, subject string) (*domain.ClientConsent, error)
}
type clientConsentRepo struct {
db *gorm.DB
}
func NewClientConsentRepository(db *gorm.DB) ClientConsentRepository {
return &clientConsentRepo{db: db}
}
func (r *clientConsentRepo) Find(ctx context.Context, clientID, subject string) (*domain.ClientConsent, error) {
var consent domain.ClientConsent
err := r.db.WithContext(ctx).
Where("client_id = ? AND subject = ?", clientID, subject).
First(&consent).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &consent, nil
}
func (r *clientConsentRepo) Upsert(ctx context.Context, consent *domain.ClientConsent) error {
return r.db.WithContext(ctx).Unscoped().
Where("client_id = ? AND subject = ?", consent.ClientID, consent.Subject).
Assign(map[string]any{
"granted_scopes": consent.GrantedScopes,
"updated_at": gorm.Expr("NOW()"),
"deleted_at": nil,
}).
FirstOrCreate(consent).Error
}
func (r *clientConsentRepo) Delete(ctx context.Context, subject, clientID string) error {
return r.db.WithContext(ctx).
Where("subject = ? AND client_id = ?", subject, clientID).
Delete(&domain.ClientConsent{}).Error
}
func (r *clientConsentRepo) DeleteByClient(ctx context.Context, clientID string) error {
return r.db.WithContext(ctx).
Where("client_id = ?", clientID).
Delete(&domain.ClientConsent{}).Error
}
func (r *clientConsentRepo) List(ctx context.Context, clientID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error) {
var consents []domain.ClientConsentWithTenantInfo
var total int64
// Base query for counting
countQuery := r.db.WithContext(ctx).Unscoped().Model(&domain.ClientConsent{}).Where("client_id = ?", clientID)
if err := countQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// Query for fetching data
query := r.db.WithContext(ctx).Unscoped().
Model(&domain.ClientConsent{}).
Select("client_consents.*, users.tenant_id, tenants.name as tenant_name").
Joins("LEFT JOIN users ON users.id::text = client_consents.subject").
Joins("LEFT JOIN tenants ON tenants.id = users.tenant_id").
Where("client_consents.client_id = ?", clientID)
err := query.Limit(limit).Offset(offset).Order("client_consents.updated_at DESC").Scan(&consents).Error
return consents, total, err
}
func (r *clientConsentRepo) ListByTenant(ctx context.Context, clientID, tenantID string, limit, offset int) ([]domain.ClientConsentWithTenantInfo, int64, error) {
var consents []domain.ClientConsentWithTenantInfo
var total int64
// Base query for counting
countQuery := r.db.WithContext(ctx).Unscoped().
Model(&domain.ClientConsent{}).
Joins("JOIN users ON users.id::text = client_consents.subject").
Where("client_consents.client_id = ? AND users.tenant_id = ?", clientID, tenantID)
if err := countQuery.Count(&total).Error; err != nil {
return nil, 0, err
}
// Query for fetching data
query := r.db.WithContext(ctx).Unscoped().
Model(&domain.ClientConsent{}).
Select("client_consents.*, users.tenant_id, tenants.name as tenant_name").
Joins("JOIN users ON users.id::text = client_consents.subject").
Joins("JOIN tenants ON tenants.id = users.tenant_id").
Where("client_consents.client_id = ? AND users.tenant_id = ?", clientID, tenantID)
err := query.
Limit(limit).
Offset(offset).
Order("client_consents.updated_at DESC").
Scan(&consents).Error
return consents, total, err
}
func (r *clientConsentRepo) ListBySubject(ctx context.Context, subject string) ([]domain.ClientConsent, error) {
var consents []domain.ClientConsent
err := r.db.WithContext(ctx).Unscoped().
Where("subject = ?", subject).
Order("updated_at DESC").
Find(&consents).Error
return consents, err
}
func (r *clientConsentRepo) ListSubjectsByClient(ctx context.Context, clientID string) ([]string, error) {
var subjects []string
err := r.db.WithContext(ctx).Unscoped().
Model(&domain.ClientConsent{}).
Distinct("subject").
Where("client_id = ?", clientID).
Order("subject ASC").
Pluck("subject", &subjects).Error
return subjects, err
}