45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
import fp from "fastify-plugin";
|
|
import type { FastifyInstance, FastifyRequest, FastifyReply } from "fastify";
|
|
import { eq, and } from "drizzle-orm";
|
|
import { db } from "../db/index.js";
|
|
import { memberships } from "../db/schema.js";
|
|
|
|
declare module "fastify" {
|
|
interface FastifyInstance {
|
|
requireAccount: (request: FastifyRequest, reply: FastifyReply) => Promise<void>;
|
|
}
|
|
interface FastifyRequest {
|
|
accountId: string;
|
|
membership: { role: string };
|
|
}
|
|
}
|
|
|
|
async function accountContextPlugin(app: FastifyInstance) {
|
|
app.decorateRequest("accountId", "");
|
|
app.decorateRequest("membership", null as unknown as { role: string });
|
|
|
|
app.decorate("requireAccount", async (request: FastifyRequest, reply: FastifyReply) => {
|
|
const accountId = (request.params as Record<string, string>).accountId;
|
|
if (!accountId || typeof accountId !== "string") {
|
|
return reply.status(400).send({ error: "accountId path parameter is required" });
|
|
}
|
|
|
|
const [membership] = await db
|
|
.select()
|
|
.from(memberships)
|
|
.where(and(eq(memberships.userId, request.user.sub), eq(memberships.accountId, accountId)));
|
|
|
|
if (!membership) {
|
|
return reply.status(403).send({ error: "You are not a member of this account" });
|
|
}
|
|
|
|
request.accountId = accountId;
|
|
request.membership = { role: membership.role };
|
|
});
|
|
}
|
|
|
|
export const accountContext = fp(accountContextPlugin, {
|
|
name: "account-context",
|
|
dependencies: ["authenticate"],
|
|
});
|