Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 27 additions & 14 deletions apps/backend/src/routes/cards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,31 @@ interface _CardWithLinks {
cardLinks: CardLinkWithPlatform[];
}

function hasErrorCode(
error: unknown,
code: string,
): error is { code: string } {
return (
typeof error === 'object' &&
error !== null &&
'code' in error &&
typeof error.code === 'string' &&
error.code === code
);
}

export async function cardRoutes(app: FastifyInstance): Promise<void> {
app.addHook('preHandler', async (request, reply) => {
const server = request.server as any;
const server = request.server;
if (typeof server?.authenticate === 'function') { await server.authenticate(request, reply); return }
if (typeof (app as any).authenticate === 'function') { await (app as any).authenticate(request, reply); return }
if (typeof app.authenticate === 'function') { await app.authenticate(request, reply); return }
try { await request.jwtVerify() } catch (_e) { reply.status(401).send({ error: 'Unauthorized' }) }
});

// ─── List Cards ───

app.get('/', async (request: FastifyRequest, reply: FastifyReply): Promise<CardResponse[] | void> => {
const userId = (request.user as { id: string }).id;
const userId = request.user.id;
try {
return await cardService.listCards(app, userId)
} catch (error) {
Expand All @@ -70,7 +83,7 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
// ─── Create Card ───

app.post('/', async (request: FastifyRequest<{ Body: CreateCardBody }>, reply: FastifyReply): Promise<Card | void> => {
const userId = (request.user as { id: string }).id;
const userId = request.user.id;
const parsed = createCardSchema.safeParse(request.body);

if (!parsed.success) {
Expand All @@ -80,16 +93,16 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
try {
const card = await cardService.createCard(app, userId, parsed.data)
return reply.status(201).send(card)
} catch (error: any) {
if (error?.code === 'OWNERSHIP') {return reply.status(403).send({ error: 'One or more links do not belong to your account' })}
} catch (error) {
if (hasErrorCode(error, 'OWNERSHIP')) {return reply.status(403).send({ error: 'One or more links do not belong to your account' })}
return handleDbError(error, request, reply)
}
});

// ─── Update Card ───

app.put('/:id', async (request: FastifyRequest<{ Params: CardParams; Body: UpdateCardBody }>, reply: FastifyReply): Promise<CardResponse> => {
const userId = (request.user as { id: string }).id;
const userId = request.user.id;
const { id } = request.params;

try {
Expand All @@ -98,27 +111,27 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
const updated = await cardService.updateCard(app, userId, id, parsed.data)
if (!updated) {return reply.status(404).send({ error: 'Card not found' })}
return updated
} catch (error: any) {
if (error?.code === 'OWNERSHIP') {return reply.status(403).send({ error: 'One or more links do not belong to your account' })}
} catch (error) {
if (hasErrorCode(error, 'OWNERSHIP')) {return reply.status(403).send({ error: 'One or more links do not belong to your account' })}
return handleDbError(error, request, reply)
}
});

// ─── Delete Card ───

app.delete('/:id', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise<void> => {
const userId = (request.user as { id: string }).id;
const userId = request.user.id;
const { id } = request.params;

try {
await cardService.deleteCard(app, userId, id)
return reply.status(204).send()
} catch (error:any) {
if (error?.code === 'NOT_FOUND') {
} catch (error) {
if (hasErrorCode(error, 'NOT_FOUND')) {
return reply.status(404).send({ error: 'Card not found' });
}

if (error?.code === 'LAST_CARD') {
if (hasErrorCode(error, 'LAST_CARD')) {
return reply.status(400).send({
error: 'Cannot delete the last remaining card. A user must have at least one card.',
});
Expand All @@ -130,7 +143,7 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
// ─── Set Default Card ───

app.put('/:id/default', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise<object | void> => {
const userId = (request.user as { id: string }).id;
const userId = request.user.id;
const { id } = request.params;

try {
Expand Down