update : Revision after first pull request on management-aspect

This commit is contained in:
percyfikri 2024-08-14 14:22:58 +07:00
parent 1774dda83e
commit 625420417e

View File

@ -1,51 +1,52 @@
import { and, eq, ilike, isNull, or, sql } from "drizzle-orm"; import { and, eq, ilike, isNull, or, sql } from "drizzle-orm";
import { Hono } from "hono"; import { Hono } from "hono";
import { z } from "zod"; import { z } from "zod";
import { HTTPException } from "hono/http-exception"; import db from "../../drizzle";
import db from "../../drizzle"; import { aspects } from "../../drizzle/schema/aspects";
import { aspects } from "../../drizzle/schema/aspects"; import { subAspects } from "../../drizzle/schema/subAspects";
import { subAspects } from "../../drizzle/schema/subAspects"; import HonoEnv from "../../types/HonoEnv";
import HonoEnv from "../../types/HonoEnv"; import requestValidator from "../../utils/requestValidator";
import requestValidator from "../../utils/requestValidator"; import authInfo from "../../middlewares/authInfo";
import authInfo from "../../middlewares/authInfo"; import checkPermission from "../../middlewares/checkPermission";
import checkPermission from "../../middlewares/checkPermission"; import { forbidden } from "../../errors/DashboardError";
import { notFound } from "../../errors/DashboardError";
// Schema for creating and updating aspects // Schema for creating and updating aspects
export const aspectFormSchema = z.object({ export const aspectFormSchema = z.object({
name: z.string().min(1).max(50), name: z.string().min(1).max(50),
subAspects: z subAspects: z
.string() .string()
.refine( .refine(
(data) => { (data) => {
try { try {
const parsed = JSON.parse(data); const parsed = JSON.parse(data);
return Array.isArray(parsed); return Array.isArray(parsed);
} catch { } catch {
return false; return false;
}
},
{
message: "Sub Aspects must be an array",
} }
) },
.optional(), {
}); message: "Sub Aspects must be an array",
}
)
.optional(),
});
export const aspectUpdateSchema = aspectFormSchema.extend({ export const aspectUpdateSchema = aspectFormSchema.extend({
subAspects: z.string().optional().or(z.literal("")), subAspects: z.string().optional().or(z.literal("")),
}); });
// Schema for creating and updating subAspects // Schema for creating and updating subAspects
export const subAspectFormSchema = z.object({ export const subAspectFormSchema = z.object({
name: z.string().min(1).max(50), name: z.string().min(1).max(50),
aspectId: z.string().uuid(), aspectId: z.string().uuid(),
}); });
export const subAspectUpdateSchema = subAspectFormSchema.extend({}); export const subAspectUpdateSchema = subAspectFormSchema.extend({});
const managementAspectRoute = new Hono<HonoEnv>() const managementAspectRoute = new Hono<HonoEnv>()
.use(authInfo) .use(authInfo)
/** /**
* Get All Aspects (With Metadata) * Get All Aspects (With Metadata)
* *
@ -53,6 +54,7 @@
* - includeTrashed: boolean (default: false) * - includeTrashed: boolean (default: false)
* - withMetadata: boolean * - withMetadata: boolean
*/ */
// Get all aspects // Get all aspects
.get( .get(
"/", "/",
@ -76,8 +78,8 @@
async (c) => { async (c) => {
const { includeTrashed, page, limit, q } = c.req.valid("query"); const { includeTrashed, page, limit, q } = c.req.valid("query");
const totalCountQuery = includeTrashed const totalCountQuery = includeTrashed
? sql<number>`(SELECT count(*) FROM ${aspects})` ? sql<number>`(SELECT count(*) FROM ${aspects})`
: sql<number>`(SELECT count(*) FROM ${aspects} WHERE ${aspects.deletedAt} IS NULL)`; : sql<number>`(SELECT count(*) FROM ${aspects} WHERE ${aspects.deletedAt} IS NULL)`;
const result = await db const result = await db
@ -110,7 +112,7 @@
}); });
} }
) )
// Get aspect by id // Get aspect by id
.get( .get(
"/:id", "/:id",
@ -124,10 +126,12 @@
async (c) => { async (c) => {
const aspectId = c.req.param("id"); const aspectId = c.req.param("id");
if (!aspectId) throw new HTTPException(400, { message: "Missing id" }); if (!aspectId)
throw notFound({
message: "Missing id",
});
const includeTrashed = const includeTrashed = c.req.query("includeTrashed")?.toLowerCase() === "true";
c.req.query("includeTrashed")?.toLowerCase() === "true";
const queryResult = await db const queryResult = await db
.select({ .select({
@ -143,15 +147,10 @@
}) })
.from(aspects) .from(aspects)
.leftJoin(subAspects, eq(aspects.id, subAspects.aspectId)) .leftJoin(subAspects, eq(aspects.id, subAspects.aspectId))
.where( .where(and(eq(aspects.id, aspectId), !includeTrashed ? isNull(aspects.deletedAt) : undefined));
and(
eq(aspects.id, aspectId),
!includeTrashed ? isNull(aspects.deletedAt) : undefined
)
);
if (!queryResult.length) if (!queryResult.length)
throw new HTTPException(404, { throw forbidden({
message: "The aspect does not exist", message: "The aspect does not exist",
}); });
@ -172,42 +171,44 @@
) )
// Create aspect // Create aspect
.post( .post("/",
"/", checkPermission("managementAspect.create"),
checkPermission("managementAspect.create"), requestValidator("json", aspectFormSchema),
requestValidator("json", aspectFormSchema),
async (c) => { async (c) => {
const aspectData = c.req.valid("json"); const aspectData = c.req.valid("json");
// Validasi untuk mengecek apakah nama aspek sudah ada // Validation to check if the aspect name already exists
const existingAspect = await db const existingAspect = await db
.select() .select()
.from(aspects) .from(aspects)
.where(ilike(aspects.name, aspectData.name)); .where(eq(aspects.name, aspectData.name));
if (existingAspect.length > 0) { if (existingAspect.length > 0) {
throw new HTTPException(400, { message: "Aspect name already existss" }); throw forbidden({
} message: "Aspect name already exists",
});
const aspect = await db }
.insert(aspects)
.values({ const aspect = await db
name: aspectData.name, .insert(aspects)
}) .values({
.returning(); name: aspectData.name,
})
if (aspectData.subAspects) { .returning();
const subAspectsArray = JSON.parse(aspectData.subAspects) as string[];
// if sub-aspects are available, parse them into a string array
if (subAspectsArray.length) { if (aspectData.subAspects) {
await db.insert(subAspects).values( const subAspectsArray = JSON.parse(aspectData.subAspects) as string[];
subAspectsArray.map((subAspect) => ({ // if there are sub-aspects, insert them into the database
aspectId: aspect[0].id, if (subAspectsArray.length) {
name: subAspect, await db.insert(subAspects).values(
})) subAspectsArray.map((subAspect) => ({
); aspectId: aspect[0].id,
} name: subAspect,
}))
);
} }
}
return c.json( return c.json(
{ {
@ -220,58 +221,61 @@
// Update aspect // Update aspect
.patch( .patch(
"/:id", "/:id",
checkPermission("managementAspect.update"), checkPermission("managementAspect.update"),
requestValidator("json", aspectUpdateSchema), requestValidator("json", aspectUpdateSchema),
async (c) => { async (c) => {
const aspectId = c.req.param("id"); const aspectId = c.req.param("id");
const aspectData = c.req.valid("json"); const aspectData = c.req.valid("json");
// Validasi untuk mengecek apakah nama aspek baru sudah ada // Validation to check if the new aspect name already exists
const existingAspect = await db const existingAspect = await db
.select() .select()
.from(aspects) .from(aspects)
.where( .where(
and( and(
ilike(aspects.name, aspectData.name), eq(aspects.name, aspectData.name),
isNull(aspects.deletedAt), isNull(aspects.deletedAt),
sql`${aspects.id} <> ${aspectId}` sql`${aspects.id} <> ${aspectId}`
) )
); );
if (existingAspect.length > 0) { if (existingAspect.length > 0) {
throw new HTTPException(400, { message: "Aspect name already exists" }); throw forbidden({
} message: "Aspect name already exists",
});
}
const aspect = await db const aspect = await db
.select() .select()
.from(aspects) .from(aspects)
.where(and(eq(aspects.id, aspectId), isNull(aspects.deletedAt))); .where(and(eq(aspects.id, aspectId), isNull(aspects.deletedAt)));
if (!aspect[0]) return c.notFound(); if (!aspect[0]) throw notFound();
await db await db
.update(aspects) .update(aspects)
.set({ .set({
...aspectData, ...aspectData,
updatedAt: new Date(), updatedAt: new Date(),
}) })
.where(eq(aspects.id, aspectId)); .where(eq(aspects.id, aspectId));
if (aspectData.subAspects) { //Update for Sub-Aspects
const subAspectsArray = JSON.parse(aspectData.subAspects) as string[]; // if (aspectData.subAspects) {
// const subAspectsArray = JSON.parse(aspectData.subAspects) as string[];
await db.delete(subAspects).where(eq(subAspects.aspectId, aspectId)); // await db.delete(subAspects).where(eq(subAspects.aspectId, aspectId));
if (subAspectsArray.length) { // if (subAspectsArray.length) {
await db.insert(subAspects).values( // await db.insert(subAspects).values(
subAspectsArray.map((subAspect) => ({ // subAspectsArray.map((subAspect) => ({
aspectId: aspectId, // aspectId: aspectId,
name: subAspect, // name: subAspect,
})) // }))
); // );
} // }
} // }
return c.json({ return c.json({
message: "Aspect updated successfully", message: "Aspect updated successfully",
@ -286,34 +290,31 @@
requestValidator( requestValidator(
"form", "form",
z.object({ z.object({
skipTrash: z.string().default("false"), // skipTrash: z.string().default("false"),
}) })
), ),
async (c) => { async (c) => {
const aspectId = c.req.param("id"); const aspectId = c.req.param("id");
const skipTrash = c.req.valid("form").skipTrash.toLowerCase() === "true"; // const skipTrash = c.req.valid("form").skipTrash.toLowerCase() === "true";
const aspect = await db const aspect = await db
.select() .select()
.from(aspects) .from(aspects)
.where(and(eq(aspects.id, aspectId), skipTrash ? undefined : isNull(aspects.deletedAt))); .where(and(eq(aspects.id, aspectId), isNull(aspects.deletedAt)));
if (!aspect[0]) if (!aspect[0])
throw new HTTPException(404, { throw notFound({
message: "The aspect is not found", message: "The aspect is not found",
}); });
if (skipTrash) { await db
await db.delete(aspects).where(eq(aspects.id, aspectId));
} else {
await db
.update(aspects) .update(aspects)
.set({ .set({
deletedAt: new Date(), deletedAt: new Date(),
}) })
.where(and(eq(aspects.id, aspectId), isNull(aspects.deletedAt))); .where(eq(aspects.id, aspectId));
}
return c.json({ return c.json({
message: "Aspect deleted successfully", message: "Aspect deleted successfully",
}); });
@ -322,8 +323,8 @@
// Undo delete // Undo delete
.patch( .patch(
"/restore/:id", "/restore/:id",
checkPermission("managementAspect.restore"), checkPermission("managementAspect.restore"),
async (c) => { async (c) => {
const aspectId = c.req.param("id"); const aspectId = c.req.param("id");
@ -332,7 +333,7 @@
if (!aspect) return c.notFound(); if (!aspect) return c.notFound();
if (!aspect.deletedAt) { if (!aspect.deletedAt) {
throw new HTTPException(400, { throw forbidden({
message: "The aspect is not deleted", message: "The aspect is not deleted",
}); });
} }
@ -345,20 +346,22 @@
} }
) )
// Get sub aspects by aspect ID // Get sub aspects by aspect ID
.get( .get(
"/subAspects/:aspectId", "/subAspects/:aspectId",
checkPermission("managementAspect.readAll"), checkPermission("managementAspect.readAll"),
async (c) => { async (c) => {
const aspectId = c.req.param("aspectId"); const aspectId = c.req.param("aspectId");
const aspect = await db const aspect = await db
.select() .select()
.from(aspects) .from(aspects)
.where(and(eq(aspects.id, aspectId), isNull(aspects.deletedAt))); .where(and(
eq(aspects.id, aspectId),
isNull(aspects.deletedAt)));
if (!aspect[0]) if (!aspect[0])
throw new HTTPException(404, { throw notFound({
message: "The aspect is not found", message: "The aspect is not found",
}); });
@ -375,34 +378,35 @@
// Create sub aspect // Create sub aspect
.post( .post(
"/subAspect", "/subAspect",
checkPermission("managementAspect.create"), checkPermission("managementAspect.create"),
requestValidator("json", subAspectFormSchema), requestValidator("json", subAspectFormSchema),
async (c) => { async (c) => {
const subAspectData = c.req.valid("json"); const subAspectData = c.req.valid("json");
// Validasi untuk mengecek apakah nama sub aspek sudah ada // Validation to check if the sub aspect name already exists
const existingSubAspect = await db const existingSubAspect = await db
.select() .select()
.from(subAspects) .from(subAspects)
.where( .where(
and( and(
ilike(subAspects.name, subAspectData.name), eq(subAspects.name, subAspectData.name),
eq(subAspects.aspectId, subAspectData.aspectId) eq(subAspects.aspectId, subAspectData.aspectId)));
)
);
if (existingSubAspect.length > 0) { if (existingSubAspect.length > 0) {
throw new HTTPException(400, { message: "Nama Sub Aspek sudah tersedia!" }); throw forbidden({ message: "Nama Sub Aspek sudah tersedia!" });
} }
const aspect = await db const [aspect] = await db
.select() .select()
.from(aspects) .from(aspects)
.where(and(eq(aspects.id, subAspectData.aspectId), isNull(aspects.deletedAt))); .where(
and(
eq(aspects.id, subAspectData.aspectId),
isNull(aspects.deletedAt)));
if (!aspect[0]) if (!aspect)
throw new HTTPException(404, { throw forbidden({
message: "The aspect is not found", message: "The aspect is not found",
}); });
@ -419,36 +423,25 @@
// Update sub aspect // Update sub aspect
.patch( .patch(
"/subAspect/:id", "/subAspect/:id", checkPermission("managementAspect.update"),
checkPermission("managementAspect.update"), requestValidator("json", subAspectUpdateSchema),
requestValidator("json", subAspectUpdateSchema),
async (c) => { async (c) => {
const subAspectId = c.req.param("id"); const subAspectId = c.req.param("id");
const subAspectData = c.req.valid("json"); const subAspectData = c.req.valid("json");
// Validasi untuk mengecek apakah nama sub aspek baru sudah ada // Validation to check if the new sub aspect name already exists
const existingSubAspect = await db const existingSubAspect = await db
.select() .select()
.from(subAspects) .from(subAspects)
.where( .where(
and( eq(subAspects.aspectId, subAspectData.aspectId));
ilike(subAspects.name, subAspectData.name),
eq(subAspects.aspectId, subAspectData.aspectId),
sql`${subAspects.id} <> ${subAspectId}`
)
);
if (existingSubAspect.length > 0) { if (existingSubAspect.length > 0) {
throw new HTTPException(400, { message: "Name Sub Aspect already exists" }); throw forbidden({ message: "Name Sub Aspect already exists" });
} }
const subAspect = await db if (!existingSubAspect[0])
.select() throw notFound({
.from(subAspects)
.where(eq(subAspects.id, subAspectId));
if (!subAspect[0])
throw new HTTPException(404, {
message: "The sub aspect is not found", message: "The sub aspect is not found",
}); });
@ -463,13 +456,12 @@
return c.json({ return c.json({
message: "Sub aspect updated successfully", message: "Sub aspect updated successfully",
}); });
} })
)
// Delete sub aspect // Delete sub aspect
.delete( .delete(
"/subAspect/:id", "/subAspect/:id",
checkPermission("managementAspect.delete"), checkPermission("managementAspect.delete"),
async (c) => { async (c) => {
const subAspectId = c.req.param("id"); const subAspectId = c.req.param("id");
@ -479,11 +471,17 @@
.where(eq(subAspects.id, subAspectId)); .where(eq(subAspects.id, subAspectId));
if (!subAspect[0]) if (!subAspect[0])
throw new HTTPException(404, { throw notFound({
message: "The sub aspect is not found", message: "The sub aspect is not found",
}); });
await db.delete(subAspects).where(eq(subAspects.id, subAspectId)); await db
.update(subAspects)
.set({
deletedAt: new Date(),
})
.where(eq(subAspects.id, subAspectId));
// await db.delete(subAspects).where(eq(subAspects.id, subAspectId));
return c.json({ return c.json({
message: "Sub aspect deleted successfully", message: "Sub aspect deleted successfully",
@ -491,5 +489,4 @@
} }
); );
export default managementAspectRoute; export default managementAspectRoute;