fix(PROJ-9): Superadmin-Tenant-NULL, GET admin/labels, from_domain-Allowlist
- labelTenantID() returns *int64 (nil for superadmin) statt int64(0) → verhindert FK-Constraint-Fehler bei tenant_id = 0 - CreateAdminLabel/CreateLabelRule: nil-Check, 400 wenn kein Tenant - GET /api/admin/labels Route + handleGetAdminLabels Handler ergänzt - from_domain in condition_field Allowlist für Label-Regeln hinzugefügt Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -241,8 +241,56 @@ func (s *Store) GetEmailIDsByLabel(ctx context.Context, labelID int64) ([]string
|
||||
// ── Admin Labels (Global) ─────────────────────────────────────────────────
|
||||
|
||||
// CreateAdminLabel creates a global label (owner_id = NULL) for a tenant.
|
||||
func (s *Store) CreateAdminLabel(ctx context.Context, name, color string, tenantID int64) (Label, error) {
|
||||
return s.CreateLabel(ctx, name, color, nil, tenantID)
|
||||
// tenantID may be nil for superadmin-global labels (stored as NULL).
|
||||
func (s *Store) CreateAdminLabel(ctx context.Context, name, color string, tenantID *int64) (Label, error) {
|
||||
var l Label
|
||||
err := s.db.QueryRow(ctx, `
|
||||
INSERT INTO labels (name, color, owner_id, tenant_id)
|
||||
VALUES ($1, $2, NULL, $3)
|
||||
RETURNING id, name, color, owner_id, tenant_id, created_at
|
||||
`, name, color, tenantID).Scan(&l.ID, &l.Name, &l.Color, &l.OwnerID, &l.TenantID, &l.CreatedAt)
|
||||
if err != nil {
|
||||
return Label{}, fmt.Errorf("labelstore: create admin label: %w", err)
|
||||
}
|
||||
l.IsGlobal = true
|
||||
return l, nil
|
||||
}
|
||||
|
||||
// GetAdminLabels returns all global labels (owner_id IS NULL) for superadmin
|
||||
// (tenantID == nil) or for a specific tenant.
|
||||
func (s *Store) GetAdminLabels(ctx context.Context, tenantID *int64) ([]Label, error) {
|
||||
var rows interface{ Next() bool; Scan(...any) error; Close(); Err() error }
|
||||
var err error
|
||||
if tenantID == nil {
|
||||
rows, err = s.db.Query(ctx, `
|
||||
SELECT id, name, color, owner_id, tenant_id, created_at
|
||||
FROM labels
|
||||
WHERE owner_id IS NULL AND tenant_id IS NULL
|
||||
ORDER BY name
|
||||
`)
|
||||
} else {
|
||||
rows, err = s.db.Query(ctx, `
|
||||
SELECT id, name, color, owner_id, tenant_id, created_at
|
||||
FROM labels
|
||||
WHERE owner_id IS NULL AND tenant_id = $1
|
||||
ORDER BY name
|
||||
`, *tenantID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("labelstore: get admin labels: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var labels []Label
|
||||
for rows.Next() {
|
||||
var l Label
|
||||
if err := rows.Scan(&l.ID, &l.Name, &l.Color, &l.OwnerID, &l.TenantID, &l.CreatedAt); err != nil {
|
||||
return nil, fmt.Errorf("labelstore: scan admin label: %w", err)
|
||||
}
|
||||
l.IsGlobal = true
|
||||
labels = append(labels, l)
|
||||
}
|
||||
return labels, rows.Err()
|
||||
}
|
||||
|
||||
// ── Label Rules ───────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user