stack/apps/backend/src/lib/request-checks.tsx
BilalG1 609579abab
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
DB migration compat / Check if migrations changed (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests (Local Emulator) / E2E Tests (Local Emulator, Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Runs E2E Fallback Tests / E2E Fallback Tests (Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Lint & build / lint_and_build (24) (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / No migration changes (skipped) (push) Has been cancelled
feat(hexclave): PR 3 — native @hexclave/* source rename + delete dual-publish wiring (#1482)
2026-05-29 15:21:59 -07:00

228 lines
5.4 KiB
TypeScript

import { StandardOAuthProviderType } from "@/generated/prisma/client";
import { KnownErrors } from "@hexclave/shared";
import { StatusError } from "@hexclave/shared/dist/utils/errors";
import { ProviderType, standardProviders } from "@hexclave/shared/dist/utils/oauth";
import { typedToUppercase } from "@hexclave/shared/dist/utils/strings";
import { listPermissions } from "./permissions";
import { Tenancy } from "./tenancies";
import { PrismaTransaction } from "./types";
async function _getTeamMembership(
tx: PrismaTransaction,
options: {
tenancyId: string,
teamId: string, userId: string,
}
) {
return await tx.teamMember.findUnique({
where: {
tenancyId_projectUserId_teamId: {
tenancyId: options.tenancyId,
projectUserId: options.userId,
teamId: options.teamId,
},
},
});
}
export async function ensureTeamMembershipExists(
tx: PrismaTransaction,
options: {
tenancyId: string,
teamId: string,
userId: string,
}
) {
await ensureUserExists(tx, { tenancyId: options.tenancyId, userId: options.userId });
const member = await _getTeamMembership(tx, options);
if (!member) {
throw new KnownErrors.TeamMembershipNotFound(options.teamId, options.userId);
}
}
export async function ensureTeamMembershipDoesNotExist(
tx: PrismaTransaction,
options: {
tenancyId: string,
teamId: string,
userId: string,
}
) {
const member = await _getTeamMembership(tx, options);
if (member) {
throw new KnownErrors.TeamMembershipAlreadyExists();
}
}
export async function ensureTeamExists(
tx: PrismaTransaction,
options: {
tenancyId: string,
teamId: string,
}
) {
const team = await tx.team.findUnique({
where: {
tenancyId_teamId: {
tenancyId: options.tenancyId,
teamId: options.teamId,
},
},
});
if (!team) {
throw new KnownErrors.TeamNotFound(options.teamId);
}
}
export async function ensureUserTeamPermissionExists(
tx: PrismaTransaction,
options: {
tenancy: Tenancy,
teamId: string,
userId: string,
permissionId: string,
errorType: 'required' | 'not-exist',
recursive: boolean,
}
) {
await ensureTeamMembershipExists(tx, {
tenancyId: options.tenancy.id,
teamId: options.teamId,
userId: options.userId,
});
const result = await listPermissions(tx, {
scope: 'team',
tenancy: options.tenancy,
teamId: options.teamId,
userId: options.userId,
permissionId: options.permissionId,
recursive: options.recursive,
});
if (result.length === 0) {
if (options.errorType === 'not-exist') {
throw new KnownErrors.TeamPermissionNotFound(options.teamId, options.userId, options.permissionId);
} else {
throw new KnownErrors.TeamPermissionRequired(options.teamId, options.userId, options.permissionId);
}
}
}
export async function ensureProjectPermissionExists(
tx: PrismaTransaction,
options: {
tenancy: Tenancy,
userId: string,
permissionId: string,
errorType: 'required' | 'not-exist',
recursive: boolean,
}
) {
await ensureUserExists(tx, {
tenancyId: options.tenancy.id,
userId: options.userId,
});
const result = await listPermissions(tx, {
scope: 'project',
tenancy: options.tenancy,
userId: options.userId,
permissionId: options.permissionId,
recursive: options.recursive,
});
if (result.length === 0) {
if (options.errorType === 'not-exist') {
throw new KnownErrors.PermissionNotFound(options.permissionId);
} else {
throw new KnownErrors.ProjectPermissionRequired(options.userId, options.permissionId);
}
}
}
export async function ensureUserExists(
tx: PrismaTransaction,
options: {
tenancyId: string,
userId: string,
}
) {
const user = await tx.projectUser.findUnique({
where: {
tenancyId_projectUserId: {
tenancyId: options.tenancyId,
projectUserId: options.userId,
},
},
});
if (!user) {
throw new KnownErrors.UserNotFound();
}
}
export function ensureStandardProvider(
providerId: ProviderType
): Lowercase<StandardOAuthProviderType> {
if (!standardProviders.includes(providerId as any)) {
throw new KnownErrors.InvalidStandardOAuthProviderId(providerId);
}
return providerId as any;
}
export async function ensureContactChannelDoesNotExists(
tx: PrismaTransaction,
options: {
tenancyId: string,
userId: string,
type: 'email',
value: string,
}
) {
const contactChannel = await tx.contactChannel.findUnique({
where: {
tenancyId_projectUserId_type_value: {
tenancyId: options.tenancyId,
projectUserId: options.userId,
type: typedToUppercase(options.type),
value: options.value,
},
},
});
if (contactChannel) {
throw new StatusError(StatusError.BadRequest, 'Contact channel already exists');
}
}
export async function ensureContactChannelExists(
tx: PrismaTransaction,
options: {
tenancyId: string,
userId: string,
contactChannelId: string,
}
) {
const contactChannel = await tx.contactChannel.findUnique({
where: {
tenancyId_projectUserId_id: {
tenancyId: options.tenancyId,
projectUserId: options.userId,
id: options.contactChannelId,
},
},
});
if (!contactChannel) {
throw new StatusError(StatusError.BadRequest, 'Contact channel not found');
}
return contactChannel;
}