@premieroctet/next-admin
Version:
Next-Admin provides a customizable and turnkey admin dashboard for applications built with Next.js and powered by the Prisma ORM. It aims to simplify the development process by providing a turnkey admin system that can be easily integrated into your proje
123 lines (122 loc) • 5.22 kB
JavaScript
import { PrismaClientKnownRequestError, PrismaClientValidationError } from "@prisma/client/runtime/library";
import { Permission } from "../types.mjs";
import { hasPermission } from "../utils/permissions.mjs";
import { getDataItem } from "../utils/prisma.mjs";
import { formatId, formattedFormData, getModelIdProperty, parseFormData } from "../utils/server.mjs";
import { uncapitalize } from "../utils/tools.mjs";
import { validate } from "../utils/validator.mjs";
const deleteResource = async ({ prisma, resource, body, modelOptions })=>{
const modelIdProperty = getModelIdProperty(resource);
if (modelOptions?.middlewares?.delete) {
const resources = await prisma[uncapitalize(resource)].findMany({
where: {
[modelIdProperty]: {
in: body.map((id)=>formatId(resource, id.toString()))
}
}
});
const middlewareExec = await Promise.allSettled(resources.map(async (res)=>{
const isSuccessDelete = await modelOptions?.middlewares?.delete?.(res);
return isSuccessDelete;
}));
if (middlewareExec.some((exec)=>"rejected" === exec.status || false === exec.value)) return false;
}
return prisma[uncapitalize(resource)].deleteMany({
where: {
[modelIdProperty]: {
in: body.map((id)=>formatId(resource, id.toString()))
}
}
});
};
const submitResource = async ({ prisma, resource, body, id, options, schema })=>{
const { __admin_redirect: redirect, ...formValues } = body;
const schemaDefinition = schema.definitions[resource];
const parsedFormData = parseFormData(formValues, schemaDefinition, options?.model?.[resource]?.edit?.fields);
const resourceIdField = getModelIdProperty(resource);
const fields = options?.model?.[resource]?.edit?.fields;
try {
validate(parsedFormData, fields);
const { formattedData, complementaryFormattedData, errors } = await formattedFormData(formValues, schema, resource, id, fields, prisma);
if (errors.length) return {
error: options?.model?.[resource]?.edit?.submissionErrorMessage ?? "Submission error",
validation: errors.map((error)=>({
property: error.field,
message: error.message
}))
};
if (!!id) {
if (!hasPermission(options?.model?.[resource], Permission.EDIT)) return {
error: "Unable to update items of this model"
};
await prisma.$transaction(async (client)=>{
let canEdit = true;
if (options?.model?.[resource]?.middlewares?.edit) {
const currentData = await prisma[uncapitalize(resource)].findUniqueOrThrow({
where: {
[resourceIdField]: formatId(resource, id.toString())
}
});
canEdit = await options?.model?.[resource]?.middlewares?.edit(formattedData, currentData);
}
if (!canEdit) throw new Error("Unable to edit this item");
await prisma[resource].update({
where: {
[resourceIdField]: id
},
data: formattedData
});
});
const { data, relationshipsRawData } = await getDataItem({
prisma,
resource,
resourceId: id,
options
});
return {
updated: true,
data,
redirect: "list" === redirect,
relationshipsRawData
};
}
if (!hasPermission(options?.model?.[resource], Permission.CREATE)) return {
error: "Unable to create items of this model"
};
const data = await prisma[resource].create({
data: formattedData
});
await prisma[resource].update({
where: {
[resourceIdField]: data[resourceIdField]
},
data: complementaryFormattedData
});
const { data: responseData, relationshipsRawData } = await getDataItem({
prisma,
resource,
resourceId: data[resourceIdField],
options
});
return {
created: true,
createdId: data[resourceIdField],
data: responseData,
redirect: "list" === redirect,
relationshipsRawData
};
} catch (error) {
if (error.constructor.name === PrismaClientValidationError.name || error.constructor.name === PrismaClientKnownRequestError.name || "ValidationError" === error.name) {
let data = parsedFormData;
if ("ValidationError" === error.name) error.errors.map((error)=>{
data[error.property] = formValues[error.property];
});
return {
error: error.message,
validation: error.errors
};
}
throw error;
}
};
export { deleteResource, submitResource };