All files / apps/web/src/handlers/receipts utils.ts

100% Statements 20/20
100% Branches 4/4
100% Functions 11/11
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85                        16x         32x 18x   14x     14x     14x     14x         14x               14x 4x   10x             10x     16x     20x   16x       29x     29x             29x     29x         29x    
import type { QueryCreator } from "kysely";
import type { z } from "zod";
 
import type { Database } from "~db/database";
import type { UserId } from "~db/ids";
import type { DB } from "~db/types.gen";
import type { assignableRoleSchema } from "~web/handlers/validation";
import { roleSchema } from "~web/handlers/validation";
 
export type Role = z.infer<typeof roleSchema>;
export type AssignableRole = z.infer<typeof assignableRoleSchema>;
 
export const getAccessRole = async (
	database: Database,
	receipt: { ownerUserId: string; id: string },
	userId: string,
): Promise<Role | undefined> => {
	if (receipt.ownerUserId === userId) {
		return "owner";
	}
	const participant = await database
		.selectFrom("receiptParticipants")
		.innerJoin("peers", (jb) =>
			jb.onRef("peers.id", "=", "receiptParticipants.peerId"),
		)
		.innerJoin("users", (jb) =>
			jb.onRef("users.id", "=", "peers.connectedUserId"),
		)
		.innerJoin("peers as reciprocalPeers", (jb) =>
			jb
				.onRef("reciprocalPeers.ownerUserId", "=", "peers.connectedUserId")
				.onRef("reciprocalPeers.connectedUserId", "=", "peers.ownerUserId"),
		)
		.where((eb) =>
			eb.and({
				"users.id": userId,
				receiptId: receipt.id,
			}),
		)
		.select("receiptParticipants.role")
		.limit(1)
		.executeTakeFirst();
	if (!participant) {
		return;
	}
	const parsed = roleSchema.safeParse(participant.role);
	/* c8 ignore start */
	if (!parsed.success) {
		// TODO: add database-level validation
		return;
	}
	/* c8 ignore stop */
	return parsed.data;
};
 
export const getOwnReceipts = (
	database: Database | QueryCreator<DB>,
	ownerUserId: UserId,
) => database.selectFrom("receipts").where("ownerUserId", "=", ownerUserId);
 
export const getParticipantsReceipts = (
	database: Database | QueryCreator<DB>,
	ownerUserId: UserId,
) =>
	database
		.selectFrom("peers")
		.where((eb) =>
			eb("peers.connectedUserId", "=", ownerUserId).and(
				"peers.ownerUserId",
				"<>",
				ownerUserId,
			),
		)
		.innerJoin("receiptParticipants", (jb) =>
			jb.onRef("receiptParticipants.peerId", "=", "peers.id"),
		)
		.innerJoin("peers as reciprocalPeers", (jb) =>
			jb
				.onRef("reciprocalPeers.ownerUserId", "=", "peers.connectedUserId")
				.onRef("reciprocalPeers.connectedUserId", "=", "peers.ownerUserId"),
		)
		.innerJoin("receipts", (jb) =>
			jb.onRef("receipts.id", "=", "receiptParticipants.receiptId"),
		);