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:
sysops
2026-04-04 10:42:06 +02:00
parent 7e1e58e1e4
commit 030752157b
2 changed files with 98 additions and 12 deletions
+50 -2
View File
@@ -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 ───────────────────────────────────────────────────────────