import { desc, eq, sql } from "drizzle-orm"; import { getDatabase } from "@/modules/core/server/db"; import { accounts, beds, joinRequests, memberships, organizationInvitations, organizations, roles, systemIncidents, } from "@/modules/core/server/schema"; import type { Account, JoinRequest, Membership, Organization, OrganizationInvitation, SystemIncident, } from "@/modules/core/types"; function iso(value: Date): string { return value.toISOString(); } function toOrganization(row: typeof organizations.$inferSelect): Organization { return { id: row.id, name: row.name, slug: row.slug, status: row.status, registrationEnabled: row.registrationEnabled, oidcEnabled: row.oidcEnabled, oidcIssuerUrl: row.oidcIssuerUrl, oidcClientId: row.oidcClientId, oidcHasClientSecret: row.oidcClientSecret.length > 0, oidcScopes: row.oidcScopes, oidcRedirectUri: row.oidcRedirectUri, oidcAvatarClaim: row.oidcAvatarClaim, oidcAutoProvision: row.oidcAutoProvision, createdAt: iso(row.createdAt), updatedAt: iso(row.updatedAt), }; } function toAccount(row: typeof accounts.$inferSelect): Account { return { id: row.id, platformRoleId: row.platformRoleId ?? undefined, name: row.name, email: row.email, avatarUrl: row.avatarUrl, role: row.platformRoleId ?? "viewer", passwordHash: row.passwordHash, passwordSalt: row.passwordSalt, status: row.status, createdAt: iso(row.createdAt), updatedAt: iso(row.updatedAt), }; } function toMembership(row: typeof memberships.$inferSelect, role: typeof roles.$inferSelect): Membership { return { id: row.id, accountId: row.accountId, organizationId: row.organizationId, roleId: row.roleId, roleKey: role.key, roleLabel: role.label, status: row.status, createdAt: iso(row.createdAt), updatedAt: iso(row.updatedAt), }; } function toJoinRequest(row: { accountEmail: string; accountName: string; organizationName: string; request: typeof joinRequests.$inferSelect; }): JoinRequest { return { id: row.request.id, accountId: row.request.accountId, accountName: row.accountName, accountEmail: row.accountEmail, organizationId: row.request.organizationId, organizationName: row.organizationName, status: row.request.status, reason: row.request.reason, reviewedByAccountId: row.request.reviewedByAccountId ?? undefined, reviewedAt: row.request.reviewedAt ? iso(row.request.reviewedAt) : undefined, createdAt: iso(row.request.createdAt), }; } function toOrganizationInvitation(row: { invitation: typeof organizationInvitations.$inferSelect; organizationName: string; roleLabel: string; }): OrganizationInvitation { return { id: row.invitation.id, organizationId: row.invitation.organizationId, organizationName: row.organizationName, roleId: row.invitation.roleId, roleLabel: row.roleLabel, email: row.invitation.email, token: row.invitation.token, status: row.invitation.status as OrganizationInvitation["status"], createdByAccountId: row.invitation.createdByAccountId ?? undefined, acceptedByAccountId: row.invitation.acceptedByAccountId ?? undefined, acceptedAt: row.invitation.acceptedAt ? iso(row.invitation.acceptedAt) : undefined, expiresAt: iso(row.invitation.expiresAt), maxUses: row.invitation.maxUses, usedCount: row.invitation.usedCount, createdAt: iso(row.invitation.createdAt), updatedAt: iso(row.invitation.updatedAt), }; } function toSystemIncident(row: typeof systemIncidents.$inferSelect): SystemIncident { return { id: row.id, organizationId: row.organizationId ?? undefined, severity: row.severity, status: row.status, title: row.title, description: row.description, source: row.source, createdAt: iso(row.createdAt), updatedAt: iso(row.updatedAt), }; } export async function listSettingsOrganizations(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = await database .select() .from(organizations) .where(params.organizationId ? eq(organizations.id, params.organizationId) : sql`true`) .orderBy(desc(organizations.createdAt)); return rows.map(toOrganization); } export async function listSettingsAccounts(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = params.organizationId ? await database .select({ account: accounts }) .from(accounts) .innerJoin(memberships, eq(memberships.accountId, accounts.id)) .where(eq(memberships.organizationId, params.organizationId)) .orderBy(desc(accounts.createdAt)) : await database.select({ account: accounts }).from(accounts).orderBy(desc(accounts.createdAt)); return rows.map((row) => toAccount(row.account)); } export async function listSettingsMemberships(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = await database .select({ membership: memberships, role: roles }) .from(memberships) .innerJoin(roles, eq(roles.id, memberships.roleId)) .where(params.organizationId ? eq(memberships.organizationId, params.organizationId) : sql`true`) .orderBy(desc(memberships.createdAt)); return rows.map((row) => toMembership(row.membership, row.role)); } export async function listSettingsJoinRequests(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = await database .select({ request: joinRequests, accountName: accounts.name, accountEmail: accounts.email, organizationName: organizations.name, }) .from(joinRequests) .innerJoin(accounts, eq(accounts.id, joinRequests.accountId)) .innerJoin(organizations, eq(organizations.id, joinRequests.organizationId)) .where(params.organizationId ? eq(joinRequests.organizationId, params.organizationId) : sql`true`) .orderBy(desc(joinRequests.createdAt)); return rows.map(toJoinRequest); } export async function listSettingsOrganizationInvitations( params: { organizationId?: string } = {}, ): Promise { const database = getDatabase(); const rows = await database .select({ invitation: organizationInvitations, organizationName: organizations.name, roleLabel: roles.label, }) .from(organizationInvitations) .innerJoin(organizations, eq(organizations.id, organizationInvitations.organizationId)) .innerJoin(roles, eq(roles.id, organizationInvitations.roleId)) .where(params.organizationId ? eq(organizationInvitations.organizationId, params.organizationId) : sql`true`) .orderBy(desc(organizationInvitations.createdAt)); return rows.map(toOrganizationInvitation); } export async function listSettingsIncidents(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = await database .select() .from(systemIncidents) .where(params.organizationId ? eq(systemIncidents.organizationId, params.organizationId) : sql`true`) .orderBy(desc(systemIncidents.createdAt)); return rows.map(toSystemIncident); } export async function countSettingsBeds(params: { organizationId?: string } = {}): Promise { const database = getDatabase(); const rows = await database .select({ count: sql`count(*)::int` }) .from(beds) .where(params.organizationId ? eq(beds.organizationId, params.organizationId) : sql`true`); return rows[0]?.count ?? 0; }