80 lines
2.7 KiB
TypeScript
80 lines
2.7 KiB
TypeScript
import { BadRequestException, Body, Controller, Headers, Post, Req } from "@nestjs/common";
|
|
import { Request } from "express";
|
|
import { ok } from "../common/response";
|
|
import { PlaidService } from "./plaid.service";
|
|
import { CurrentUser } from "../common/decorators/current-user.decorator";
|
|
import { Public } from "../common/decorators/public.decorator";
|
|
import { OpaqueIdService } from "../common/opaque-id.service";
|
|
import { ViewRefService } from "../common/view-ref.service";
|
|
import { PrismaService } from "../prisma/prisma.service";
|
|
|
|
@Controller("plaid")
|
|
export class PlaidController {
|
|
constructor(
|
|
private readonly plaidService: PlaidService,
|
|
private readonly opaqueIds: OpaqueIdService,
|
|
private readonly viewRefs: ViewRefService,
|
|
private readonly prisma: PrismaService,
|
|
) {}
|
|
|
|
@Post("link-token")
|
|
async createLinkToken(@CurrentUser() userId: string) {
|
|
const data = await this.plaidService.createLinkToken(userId);
|
|
return ok(data);
|
|
}
|
|
|
|
@Post("exchange")
|
|
async exchange(
|
|
@CurrentUser() userId: string,
|
|
@Body() payload: { publicToken: string },
|
|
) {
|
|
const data = await this.plaidService.exchangePublicTokenForUser(userId, payload.publicToken);
|
|
return ok(data);
|
|
}
|
|
|
|
@Post("update-link-token")
|
|
async createUpdateLinkToken(
|
|
@CurrentUser() userId: string,
|
|
@Body() payload: { accountId: string },
|
|
) {
|
|
const accountId = await this.resolveAccountHandle(userId, payload.accountId);
|
|
const data = await this.plaidService.createUpdateModeLinkToken(userId, accountId);
|
|
return ok(data);
|
|
}
|
|
|
|
@Post("repair-complete")
|
|
async repairComplete(
|
|
@CurrentUser() userId: string,
|
|
@Body() payload: { accountId: string },
|
|
) {
|
|
const accountId = await this.resolveAccountHandle(userId, payload.accountId);
|
|
const data = await this.plaidService.markItemRepairComplete(userId, accountId);
|
|
return ok(data);
|
|
}
|
|
|
|
@Public()
|
|
@Post("webhook")
|
|
async webhook(
|
|
@Body() payload: Record<string, unknown>,
|
|
@Headers("plaid-verification") verification: string | undefined,
|
|
@Req() request: Request & { rawBody?: Buffer },
|
|
) {
|
|
const data = await this.plaidService.handleWebhook(payload, verification, request.rawBody);
|
|
return ok(data);
|
|
}
|
|
|
|
private async resolveAccountHandle(userId: string, handle: string) {
|
|
try {
|
|
return this.opaqueIds.decode("account", userId, handle);
|
|
} catch {
|
|
const accounts = await this.prisma.account.findMany({
|
|
where: { userId, isActive: true },
|
|
select: { id: true },
|
|
});
|
|
const match = accounts.find((account) => this.viewRefs.matches(userId, "account", account.id, handle));
|
|
if (!match) throw new BadRequestException("Invalid resource identifier.");
|
|
return match.id;
|
|
}
|
|
}
|
|
}
|