Adjusted SMTP

This commit is contained in:
2026-04-11 12:21:34 +02:00
parent 9a96d74f5c
commit 97b483c121
9 changed files with 339 additions and 24 deletions

View File

@@ -35,22 +35,22 @@ function getPool(): Pool {
const MIGRATION_SQL = `
CREATE TABLE IF NOT EXISTS tenant_requests (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
zitadel_org_id TEXT NOT NULL UNIQUE,
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
zitadel_org_id TEXT NOT NULL UNIQUE,
zitadel_user_id TEXT NOT NULL,
company_name TEXT NOT NULL,
contact_name TEXT NOT NULL,
contact_email TEXT NOT NULL,
agent_name TEXT NOT NULL DEFAULT 'Assistant',
soul_md TEXT,
packages TEXT[] DEFAULT '{}',
company_name TEXT NOT NULL,
contact_name TEXT NOT NULL,
contact_email TEXT NOT NULL,
agent_name TEXT NOT NULL DEFAULT 'Assistant',
soul_md TEXT,
packages TEXT[] DEFAULT '{}',
billing_address JSONB DEFAULT '{}',
billing_notes TEXT,
status TEXT NOT NULL DEFAULT 'pending',
admin_notes TEXT,
tenant_name TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
billing_notes TEXT,
status TEXT NOT NULL DEFAULT 'pending',
admin_notes TEXT,
tenant_name TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_tenant_requests_status ON tenant_requests(status);
@@ -75,8 +75,8 @@ export async function createTenantRequest(
await ensureSchema();
const result = await getPool().query<TenantRequest>(
`INSERT INTO tenant_requests
(zitadel_org_id, zitadel_user_id, company_name, contact_name,
contact_email, agent_name, soul_md, packages, billing_address, billing_notes)
(zitadel_org_id, zitadel_user_id, company_name, contact_name,
contact_email, agent_name, soul_md, packages, billing_address, billing_notes)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING *`,
[
@@ -132,12 +132,19 @@ export async function listTenantRequests(
export async function updateTenantRequestStatus(
id: string,
status: TenantRequestStatus,
extra?: { adminNotes?: string; tenantName?: string }
extra?: { adminNotes?: string | null; tenantName?: string; clearAdminNotes?: boolean }
): Promise<TenantRequest> {
await ensureSchema();
// If clearAdminNotes is true, explicitly set admin_notes to NULL
// Otherwise use COALESCE to preserve existing value when not provided
const adminNotesExpr = extra?.clearAdminNotes
? "$2"
: "COALESCE($2, admin_notes)";
const result = await getPool().query(
`UPDATE tenant_requests
SET status = $1, admin_notes = COALESCE($2, admin_notes),
SET status = $1, admin_notes = ${adminNotesExpr},
tenant_name = COALESCE($3, tenant_name), updated_at = now()
WHERE id = $4
RETURNING *`,
@@ -147,6 +154,35 @@ export async function updateTenantRequestStatus(
return mapRow(result.rows[0]);
}
/**
* Sync provisioning statuses: for all requests with status "provisioning",
* check if the PiecedTenant CR has reached "Ready" and update to "active".
* Called from the admin requests list endpoint.
*/
export async function syncProvisioningStatuses(
checkTenantPhase: (tenantName: string) => Promise<string | null>
): Promise<void> {
await ensureSchema();
const pool = getPool();
const result = await pool.query(
"SELECT id, tenant_name FROM tenant_requests WHERE status = 'provisioning' AND tenant_name IS NOT NULL"
);
for (const row of result.rows) {
try {
const phase = await checkTenantPhase(row.tenant_name);
if (phase === "Ready" || phase === "Running") {
await pool.query(
"UPDATE tenant_requests SET status = 'active', updated_at = now() WHERE id = $1",
[row.id]
);
}
} catch (e) {
console.error(`Failed to sync status for request ${row.id}:`, e);
}
}
}
// ---------------------------------------------------------------------------
// Row mapping (snake_case → camelCase)
// ---------------------------------------------------------------------------