brackt/app/models/commissioner.ts
Claude 388071fef8
Add account deletion and multi-section settings page
- Rename /user-profile → /settings with 301 redirect from old URL
- Add multi-section settings nav (Profile, Account, API placeholder, Data & Privacy)
  reusing existing SettingsDesktopNav/SettingsMobileGridNav components
- Implement account deletion via anonymization: wipes all PII from users row,
  releases team ownerships, removes commissioner records, deletes sessions/accounts
- Add data export request form that emails privacy@brackt.com via Resend
- Add deletedAt timestamp column to users table (migration 0100)
- Add anonymizeUserAccount() to user model
- Add removeAllCommissionersByUserId() to commissioner model
- Tests for both new model functions
- Update UserMenu "Profile" link → "Settings" at /settings

https://claude.ai/code/session_017Hvmof82Xr3UwKFc3pnC4X
2026-05-10 20:28:23 +00:00

104 lines
2.9 KiB
TypeScript

import { eq, and } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { isUserAdmin } from "~/models/user";
export type Commissioner = typeof schema.commissioners.$inferSelect;
export type NewCommissioner = typeof schema.commissioners.$inferInsert;
export async function createCommissioner(
data: NewCommissioner
): Promise<Commissioner> {
const db = database();
const [commissioner] = await db
.insert(schema.commissioners)
.values(data)
.returning();
return commissioner;
}
export async function findCommissionersByLeagueId(
leagueId: string
): Promise<Commissioner[]> {
const db = database();
return await db.query.commissioners.findMany({
where: eq(schema.commissioners.leagueId, leagueId),
orderBy: (commissioners, { asc }) => [asc(commissioners.createdAt)],
});
}
export async function findCommissionersByUserId(
userId: string
): Promise<Commissioner[]> {
const db = database();
return await db.query.commissioners.findMany({
where: eq(schema.commissioners.userId, userId),
orderBy: (commissioners, { desc }) => [desc(commissioners.createdAt)],
});
}
export async function hasCommissionerRecord(
leagueId: string,
userId: string
): Promise<boolean> {
const db = database();
const commissioner = await db.query.commissioners.findFirst({
where: and(
eq(schema.commissioners.leagueId, leagueId),
eq(schema.commissioners.userId, userId)
),
});
return !!commissioner;
}
export async function isCommissioner(
leagueId: string,
userId: string
): Promise<boolean> {
const db = database();
const [isAdmin, commissioner] = await Promise.all([
isUserAdmin(userId),
db.query.commissioners.findFirst({
where: and(
eq(schema.commissioners.leagueId, leagueId),
eq(schema.commissioners.userId, userId)
),
}),
]);
return isAdmin || !!commissioner;
}
export async function countCommissionersByLeagueId(
leagueId: string
): Promise<number> {
const db = database();
const commissioners = await db.query.commissioners.findMany({
where: eq(schema.commissioners.leagueId, leagueId),
});
return commissioners.length;
}
export async function deleteCommissioner(id: string): Promise<void> {
const db = database();
await db.delete(schema.commissioners).where(eq(schema.commissioners.id, id));
}
export async function removeCommissionerByLeagueAndUser(
leagueId: string,
userId: string
): Promise<void> {
const db = database();
await db
.delete(schema.commissioners)
.where(
and(
eq(schema.commissioners.leagueId, leagueId),
eq(schema.commissioners.userId, userId)
)
);
}
export async function removeAllCommissionersByUserId(userId: string): Promise<void> {
const db = database();
await db.delete(schema.commissioners).where(eq(schema.commissioners.userId, userId));
}