Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/modules/rows/routes/Rows_Share.server.ts
T

142 lines
5.4 KiB
TypeScript

import { Tenant } from "@toolctrl/db/prisma-browser";
import { LoaderFunctionArgs, redirect, ActionFunction } from "react-router";
import type { TFunction } from "i18next";
import { MetaTagsDto } from "~/application/dtos/seo/MetaTagsDto";
import { RowAccess } from "~/application/enums/entities/RowAccess";
import { EntitiesApi } from "~/utils/api/.server/EntitiesApi";
import { RowPermissionsApi } from "~/utils/api/.server/RowPermissionsApi";
import { RowsApi } from "~/utils/api/.server/RowsApi";
import UrlUtils from "~/utils/app/UrlUtils";
import { adminGetAllTenants, getTenant } from "~/utils/db/tenants.db.server";
import { UserWithDetails, getUser, getUsersByTenant } from "~/utils/db/users.db.server";
import RowHelper from "~/utils/helpers/RowHelper";
import RowsRequestUtils from "../utils/RowsRequestUtils";
import EventsService from "~/modules/events/services/.server/EventsService";
import { RowSharedDto } from "~/modules/events/dtos/RowSharedDto";
import { getRowsRouteErrorCode, getRowsRouteErrorStatus, translateRowsRouteError } from "./Rows_Error.server";
const allowedShareTypes = ["tenant", "user", "role", "group"] as const;
type ShareType = (typeof allowedShareTypes)[number];
function getShareType(value: FormDataEntryValue | null): ShareType | null {
const type = value?.toString();
return allowedShareTypes.includes(type as ShareType) ? (type as ShareType) : null;
}
export namespace Rows_Share {
export type ActionData = {
success?: string;
error?: string;
errorCode?: import("~/utils/api/.server/RowsApi").RowApiErrorCode;
};
export type LoaderData = {
meta: MetaTagsDto;
rowData: RowsApi.GetRowData;
routes: EntitiesApi.Routes;
tenants: Tenant[];
users: UserWithDetails[];
};
export const loader = async ({ request, params }: LoaderFunctionArgs) => {
const { t, userId, tenantId, entity } = await RowsRequestUtils.getLoader({ request, params });
if (!entity.isAutogenerated || entity.type === "system") {
throw redirect(tenantId ? UrlUtils.currentTenantUrl(params, "404") : "/404");
}
const rowData = await RowsApi.get(params.id!, {
entity,
tenantId,
userId,
});
if (!rowData.rowPermissions.canUpdate) {
throw Error(t("shared.unauthorized"));
}
let tenants: Tenant[] = [];
if (tenantId) {
tenants.push((await getTenant(tenantId))!);
} else {
tenants = await adminGetAllTenants();
}
const data: LoaderData = {
meta: [{ title: `${t("shared.share")} | ${RowHelper.getTextDescription({ entity, item: rowData.item, t })} | ${process.env.APP_NAME}` }],
rowData,
routes: EntitiesApi.getNoCodeRoutes({ request, params }),
tenants,
users: (await getUsersByTenant(tenantId)).filter((f) => f.id !== userId),
};
return Response.json(data);
};
export const action: ActionFunction = async ({ request, params }) => {
const { t, entity, tenantId, userId, form } = await RowsRequestUtils.getAction({ request, params });
const user = await getUser(userId);
if (!user) {
throw redirect(tenantId ? UrlUtils.currentTenantUrl(params, "404") : "/404");
}
const action = form.get("action");
if (!entity.isAutogenerated || entity.type === "system") {
throw redirect(tenantId ? UrlUtils.currentTenantUrl(params, "404") : "/404");
}
const rowData = await RowsApi.get(params.id!, {
entity,
tenantId,
userId,
});
if (!rowData.rowPermissions.canUpdate) {
throw Error(t("shared.unauthorized"));
}
if (action === "share") {
const type = getShareType(form.get("type"));
if (!type) {
return Response.json({ error: t("shared.invalidForm") }, { status: 400 });
}
const id = form.get("id")?.toString() ?? "";
const access = form.get("access")?.toString() as RowAccess;
try {
await RowPermissionsApi.share(rowData.item, {
type,
id,
access,
}, { currentTenantId: tenantId });
await EventsService.create({
request,
event: "row.shared",
tenantId,
userId,
data: {
id: rowData.item.id,
title: RowHelper.getTextDescription({ entity, item: rowData.item, t }),
entity: { id: entity.id, name: entity.name, slug: entity.slug, title: entity.title },
type,
to: id,
access,
user: { id: user.id, email: user.email },
} satisfies RowSharedDto,
});
return Response.json({ success: t("shared.saved") });
} catch (error: unknown) {
return rowActionError(t, error);
}
} else if (action === "set-access") {
const id = form.get("id")?.toString() ?? "";
const access = form.get("access")?.toString() as RowAccess;
await RowPermissionsApi.setAccessForRow(rowData.item.id, id, access);
return Response.json({ success: t("shared.saved") });
} else if (action === "remove") {
const id = form.get("id")?.toString() ?? "";
await RowPermissionsApi.delForRow(rowData.item.id, id);
return Response.json({ success: t("shared.deleted") });
} else {
return Response.json({ error: t("shared.invalidForm") }, { status: 400 });
}
};
}
function rowActionError(t: TFunction, error: unknown) {
return Response.json(
{ error: translateRowsRouteError(t, error), errorCode: getRowsRouteErrorCode(error) } satisfies Rows_Share.ActionData,
{ status: getRowsRouteErrorStatus(error) }
);
}