package migration import ( "context" "fmt" "strings" ) const adminConsentStatePrefix = "project:" // MicrosoftAdminConsentRecord stores the outcome of a Microsoft admin consent redirect. type MicrosoftAdminConsentRecord struct { TenantID string ClientID string ProjectID string Granted bool ErrorCode string ErrorDescription string } // MicrosoftAdminConsent is a persisted tenant-level admin consent row. type MicrosoftAdminConsent struct { TenantID string `json:"tenant_id"` ClientID string `json:"client_id"` ProjectID string `json:"project_id,omitempty"` Granted bool `json:"granted"` ErrorCode string `json:"error_code,omitempty"` ErrorDescription string `json:"error_description,omitempty"` ConsentedAt string `json:"consented_at"` UpdatedAt string `json:"updated_at"` } func EncodeAdminConsentState(projectID string) string { projectID = strings.TrimSpace(projectID) if projectID == "" { return "" } return adminConsentStatePrefix + projectID } func ParseAdminConsentProjectID(state string) string { state = strings.TrimSpace(state) if !strings.HasPrefix(state, adminConsentStatePrefix) { return "" } return strings.TrimSpace(strings.TrimPrefix(state, adminConsentStatePrefix)) } func (s *Service) RecordMicrosoftAdminConsent(ctx context.Context, in MicrosoftAdminConsentRecord) error { if s.db == nil { return fmt.Errorf("database not configured") } tenantID := strings.TrimSpace(in.TenantID) clientID := strings.TrimSpace(in.ClientID) projectID := strings.TrimSpace(in.ProjectID) if tenantID == "" { return fmt.Errorf("tenant id required") } if clientID == "" { return fmt.Errorf("client id required") } tx, err := s.db.Begin(ctx) if err != nil { return err } defer tx.Rollback(ctx) _, err = tx.Exec(ctx, ` INSERT INTO migration_microsoft_admin_consents ( tenant_id, client_id, project_id, granted, error_code, error_description ) VALUES ($1, $2, NULLIF($3, '')::uuid, $4, $5, $6) ON CONFLICT (tenant_id, client_id) DO UPDATE SET project_id = COALESCE(EXCLUDED.project_id, migration_microsoft_admin_consents.project_id), granted = EXCLUDED.granted, error_code = EXCLUDED.error_code, error_description = EXCLUDED.error_description, consented_at = NOW(), updated_at = NOW() `, tenantID, clientID, projectID, in.Granted, in.ErrorCode, in.ErrorDescription) if err != nil { return err } if projectID != "" { if in.Granted { _, err = tx.Exec(ctx, ` UPDATE migration_projects SET microsoft_tenant_id = $2, microsoft_admin_consent_at = NOW(), microsoft_admin_consent_error = '', updated_at = NOW() WHERE id = $1::uuid `, projectID, tenantID) } else { errMsg := strings.TrimSpace(in.ErrorDescription) if errMsg == "" { errMsg = strings.TrimSpace(in.ErrorCode) } _, err = tx.Exec(ctx, ` UPDATE migration_projects SET microsoft_tenant_id = CASE WHEN microsoft_tenant_id = '' THEN $2 ELSE microsoft_tenant_id END, microsoft_admin_consent_error = $3, updated_at = NOW() WHERE id = $1::uuid `, projectID, tenantID, errMsg) } if err != nil { return err } } return tx.Commit(ctx) } func (s *Service) ListMicrosoftAdminConsents(ctx context.Context) ([]MicrosoftAdminConsent, error) { rows, err := s.db.Query(ctx, ` SELECT tenant_id, client_id, COALESCE(project_id::text, ''), granted, error_code, error_description, consented_at::text, updated_at::text FROM migration_microsoft_admin_consents ORDER BY updated_at DESC `) if err != nil { return nil, err } defer rows.Close() var out []MicrosoftAdminConsent for rows.Next() { var row MicrosoftAdminConsent if err := rows.Scan( &row.TenantID, &row.ClientID, &row.ProjectID, &row.Granted, &row.ErrorCode, &row.ErrorDescription, &row.ConsentedAt, &row.UpdatedAt, ); err != nil { return nil, err } out = append(out, row) } return out, rows.Err() }