Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/api/.server/RowPermissionsApi.ts
T

159 lines
5.3 KiB
TypeScript

import { RowAccess, RowAccessTypes } from "~/application/enums/entities/RowAccess";
import {
createRowPermission,
deleteRowPermissionByIdForRow,
getRowPermissions,
updateRowPermissionForRow,
} from "../../db/permissions/rowPermissions.db.server";
import { DefaultVisibility } from "~/application/dtos/shared/DefaultVisibility";
import { Row } from "@toolctrl/db/prisma-browser";
import { getGroup } from "~/utils/db/permissions/groups.db.server";
import { getRole } from "~/utils/db/permissions/roles.db.server";
import { getTenant, getTenantUserByIds } from "~/utils/db/tenants.db.server";
export namespace RowPermissionsApi {
type ShareData = { type: "tenant" | "user" | "role" | "group" | "public"; id?: string; access: RowAccess };
type ShareScope = { currentTenantId?: string | null };
export async function shareWithDefault(row: Row, defaultVisibility: DefaultVisibility) {
if (defaultVisibility === "tenant" && row.tenantId) {
await shareWithTenant(row, row.tenantId, "edit");
}
if (defaultVisibility === "public") {
return await shareWithPublic(row, "view");
}
}
export async function share(row: Row, data: ShareData, scope: ShareScope = {}) {
await validateShareTarget(data, scope);
const permission = {
tenantId: data.type === "tenant" ? data.id : null,
roleId: data.type === "role" ? data.id : null,
groupId: data.type === "group" ? data.id : null,
userId: data.type === "user" ? data.id : null,
public: data.type === "public",
access: data.access,
};
if (data.type !== "public" && !permission.tenantId && !permission.roleId && !permission.groupId && !permission.userId) {
throw Error("Invalid permission");
}
const permissions = await getRowPermissions(row.id);
const existing = permissions.find(
(f) =>
f.tenantId === permission.tenantId &&
f.roleId === permission.roleId &&
f.groupId === permission.groupId &&
f.userId === permission.userId &&
f.public === permission.public
);
if (data.type === "user" && data.id === row?.createdByUserId) {
return;
} else if (existing) {
return existing;
}
const create = await createRowPermission({
rowId: row.id,
...permission,
});
return create;
}
export async function validateShareTarget(data: ShareData, scope: ShareScope = {}) {
validateAccess(data.access);
if (data.type !== "tenant" && data.type !== "user" && data.type !== "role" && data.type !== "group" && data.type !== "public") {
throw Error("Invalid permission target");
}
if (data.type !== "public" && data.id === "public") {
throw Error("Invalid permission target");
}
if (data.type === "public" && data.id) {
throw Error("Invalid permission target");
}
if (data.type === "public") {
return;
}
if (!data.id) {
throw Error("Invalid permission target");
}
const { currentTenantId } = scope;
if (data.type === "tenant") {
if (currentTenantId && data.id !== currentTenantId) {
throw Error("Invalid permission target");
}
if (currentTenantId === null && !(await getTenant(data.id))) {
throw Error("Invalid permission target");
}
return;
}
if (data.type === "user") {
if (currentTenantId && !(await getTenantUserByIds(currentTenantId, data.id))) {
throw Error("Invalid permission target");
}
return;
}
if (data.type === "group") {
if (!(await getGroup(data.id, currentTenantId))) {
throw Error("Invalid permission target");
}
return;
}
const role = await getRole(data.id);
if (!role || (currentTenantId && role.type !== "app")) {
throw Error("Invalid permission target");
}
}
export function validateAccess(access: RowAccess) {
if (!RowAccessTypes.includes(access)) {
throw Error("Invalid permission access");
}
}
export async function shareWithTenant(row: Row, tenantId: string, access: RowAccess) {
return await share(row, {
type: "tenant",
id: tenantId,
access,
}, { currentTenantId: tenantId });
}
export async function shareWithUser(row: Row, userId: string, access: RowAccess) {
return await share(row, {
type: "user",
id: userId,
access,
});
}
export async function shareWithRole(row: Row, roleId: string, access: RowAccess) {
return await share(row, {
type: "role",
id: roleId,
access,
});
}
export async function shareWithGroup(row: Row, groupId: string, access: RowAccess) {
return await share(row, {
type: "group",
id: groupId,
access,
});
}
export async function shareWithPublic(row: Row, access: RowAccess) {
return await share(row, {
type: "public",
access,
});
}
export async function setAccessForRow(rowId: string, id: string, access: RowAccess) {
validateAccess(access);
const updated = await updateRowPermissionForRow(rowId, id, { access });
if (updated.count !== 1) {
throw Error("Permission not found");
}
return updated;
}
export async function delForRow(rowId: string, id: string) {
const deleted = await deleteRowPermissionByIdForRow(rowId, id);
if (deleted.count !== 1) {
throw Error("Permission not found");
}
return deleted;
}
}