Merge pull request #21 from digitalsolutiongroup/feat/assessment-request-management
develop API assessment request management
This commit is contained in:
commit
e7a425aa0b
|
|
@ -47,6 +47,15 @@ const permissionsData = [
|
||||||
{
|
{
|
||||||
code: "questions.restore",
|
code: "questions.restore",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
code :"assessmentRequestManagement.readAll",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code: "assessmentRequestManagement.update",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
code :"assessmentRequestManagement.read",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
code: "managementAspect.readAll",
|
code: "managementAspect.readAll",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { relations } from "drizzle-orm";
|
||||||
import { respondents } from "./respondents";
|
import { respondents } from "./respondents";
|
||||||
import { users } from "./users";
|
import { users } from "./users";
|
||||||
|
|
||||||
const statusEnum = pgEnum("status", ["menunggu konfirmasi", "disetujui", "ditolak", "selesai"]);
|
const statusEnum = pgEnum("status", ["menunggu konfirmasi", "diterima", "ditolak", "selesai"]);
|
||||||
|
|
||||||
export const assessments = pgTable("assessments", {
|
export const assessments = pgTable("assessments", {
|
||||||
id: varchar("id", { length: 50 })
|
id: varchar("id", { length: 50 })
|
||||||
|
|
@ -17,6 +17,8 @@ export const assessments = pgTable("assessments", {
|
||||||
validatedBy: varchar("validatedBy"),
|
validatedBy: varchar("validatedBy"),
|
||||||
validatedAt: timestamp("validatedAt", { mode: "date" }),
|
validatedAt: timestamp("validatedAt", { mode: "date" }),
|
||||||
createdAt: timestamp("createdAt", { mode: "date" }).defaultNow(),
|
createdAt: timestamp("createdAt", { mode: "date" }).defaultNow(),
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
// Query Tools in PosgreSQL
|
// Query Tools in PosgreSQL
|
||||||
// CREATE TYPE status AS ENUM ('menunggu konfirmasi', 'disetujui', 'ditolak', 'selesai');
|
// CREATE TYPE status AS ENUM ('menunggu konfirmasi', 'diterima', 'ditolak', 'selesai');
|
||||||
|
|
@ -22,6 +22,7 @@ import assessmentResultRoute from "./routes/assessmentResult/route";
|
||||||
import assessmentRequestRoute from "./routes/assessmentRequest/route";
|
import assessmentRequestRoute from "./routes/assessmentRequest/route";
|
||||||
import forgotPasswordRoutes from "./routes/forgotPassword/route";
|
import forgotPasswordRoutes from "./routes/forgotPassword/route";
|
||||||
import assessmentsRoute from "./routes/assessments/route";
|
import assessmentsRoute from "./routes/assessments/route";
|
||||||
|
import assessmentsRequestManagementRoutes from "./routes/assessmentRequestManagement/route";
|
||||||
|
|
||||||
configDotenv();
|
configDotenv();
|
||||||
|
|
||||||
|
|
@ -92,11 +93,13 @@ const routes = app
|
||||||
.route("/assessmentRequest", assessmentRequestRoute)
|
.route("/assessmentRequest", assessmentRequestRoute)
|
||||||
.route("/forgot-password", forgotPasswordRoutes)
|
.route("/forgot-password", forgotPasswordRoutes)
|
||||||
.route("/assessments", assessmentsRoute)
|
.route("/assessments", assessmentsRoute)
|
||||||
|
.route("/assessmentRequestManagement",assessmentsRequestManagementRoutes)
|
||||||
.onError((err, c) => {
|
.onError((err, c) => {
|
||||||
if (err instanceof DashboardError) {
|
if (err instanceof DashboardError) {
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
message: err.message,
|
message: err.message,
|
||||||
|
|
||||||
errorCode: err.errorCode,
|
errorCode: err.errorCode,
|
||||||
formErrors: err.formErrors,
|
formErrors: err.formErrors,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
173
apps/backend/src/routes/assessmentRequestManagement/route.ts
Normal file
173
apps/backend/src/routes/assessmentRequestManagement/route.ts
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
import { and, eq, ilike, or, sql } from "drizzle-orm";
|
||||||
|
import { Hono } from "hono";
|
||||||
|
import checkPermission from "../../middlewares/checkPermission";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { HTTPException } from "hono/http-exception";
|
||||||
|
import db from "../../drizzle";
|
||||||
|
import { assessments } from "../../drizzle/schema/assessments";
|
||||||
|
import { respondents } from "../../drizzle/schema/respondents";
|
||||||
|
import { users } from "../../drizzle/schema/users";
|
||||||
|
import HonoEnv from "../../types/HonoEnv";
|
||||||
|
import requestValidator from "../../utils/requestValidator";
|
||||||
|
import authInfo from "../../middlewares/authInfo";
|
||||||
|
|
||||||
|
export const assessmentFormSchema = z.object({
|
||||||
|
respondentId: z.string().min(1),
|
||||||
|
status: z.enum(["menunggu konfirmasi", "diterima", "ditolak", "selesai"]),
|
||||||
|
reviewedBy: z.string().min(1),
|
||||||
|
validatedBy: z.string().min(1),
|
||||||
|
validatedAt: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const assessmentUpdateSchema = assessmentFormSchema.extend({
|
||||||
|
validatedAt: z.string().optional().or(z.literal("")),
|
||||||
|
});
|
||||||
|
|
||||||
|
const assessmentsRequestManagementRoutes = new Hono<HonoEnv>()
|
||||||
|
.use(authInfo)
|
||||||
|
/**
|
||||||
|
* Get All Assessments (With Metadata)
|
||||||
|
*
|
||||||
|
* Query params:
|
||||||
|
* - withMetadata: boolean
|
||||||
|
*/
|
||||||
|
.get(
|
||||||
|
"/",
|
||||||
|
checkPermission("assessmentRequestManagement.readAll"),
|
||||||
|
requestValidator(
|
||||||
|
"query",
|
||||||
|
z.object({
|
||||||
|
withMetadata: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.transform((v) => v?.toLowerCase() === "true"),
|
||||||
|
page: z.coerce.number().int().min(0).default(0),
|
||||||
|
limit: z.coerce.number().int().min(1).max(1000).default(10),
|
||||||
|
q: z.string().default(""),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
async (c) => {
|
||||||
|
const { page, limit, q } = c.req.valid("query");
|
||||||
|
|
||||||
|
const totalCountQuery = sql<number>`(SELECT count(*) FROM ${assessments})`;
|
||||||
|
|
||||||
|
const result = await db
|
||||||
|
.select({
|
||||||
|
idPermohonan: assessments.id,
|
||||||
|
namaResponden: users.name,
|
||||||
|
namaPerusahaan: respondents.companyName,
|
||||||
|
status: assessments.status,
|
||||||
|
tanggal: assessments.createdAt,
|
||||||
|
fullCount: totalCountQuery,
|
||||||
|
})
|
||||||
|
.from(assessments)
|
||||||
|
.leftJoin(respondents, eq(assessments.respondentId, respondents.id))
|
||||||
|
.leftJoin(users, eq(respondents.userId, users.id))
|
||||||
|
.where(
|
||||||
|
q
|
||||||
|
? or(
|
||||||
|
ilike(users.name, `%${q}%`),
|
||||||
|
ilike(respondents.companyName, `%${q}%`),
|
||||||
|
eq(assessments.id, q)
|
||||||
|
)
|
||||||
|
: undefined
|
||||||
|
)
|
||||||
|
.offset(page * limit)
|
||||||
|
.limit(limit);
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
data: result.map((d) => ({
|
||||||
|
idPermohonan: d.idPermohonan,
|
||||||
|
namaResponden: d.namaResponden,
|
||||||
|
namaPerusahaan: d.namaPerusahaan,
|
||||||
|
status: d.status,
|
||||||
|
tanggal: d.tanggal,
|
||||||
|
})),
|
||||||
|
_metadata: {
|
||||||
|
currentPage: page,
|
||||||
|
totalPages: Math.ceil(
|
||||||
|
(Number(result[0]?.fullCount) ?? 0) / limit
|
||||||
|
),
|
||||||
|
totalItems: Number(result[0]?.fullCount) ?? 0,
|
||||||
|
perPage: limit,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Get assessment by id
|
||||||
|
.get(
|
||||||
|
"/:id",
|
||||||
|
checkPermission("assessmentRequestManagement.read"),
|
||||||
|
async (c) => {
|
||||||
|
const assessmentId = c.req.param("id");
|
||||||
|
|
||||||
|
const queryResult = await db
|
||||||
|
.select({
|
||||||
|
// id: assessments.id,
|
||||||
|
tanggal: assessments.createdAt,
|
||||||
|
nama: users.name,
|
||||||
|
posisi: respondents.position,
|
||||||
|
pengalamanKerja: respondents.workExperience,
|
||||||
|
email: users.email,
|
||||||
|
namaPerusahaan: respondents.companyName,
|
||||||
|
alamat: respondents.address,
|
||||||
|
nomorTelepon: respondents.phoneNumber,
|
||||||
|
username: users.username,
|
||||||
|
status: assessments.status,
|
||||||
|
})
|
||||||
|
.from(assessments)
|
||||||
|
.leftJoin(respondents, eq(assessments.respondentId, respondents.id))
|
||||||
|
.leftJoin(users, eq(respondents.userId, users.id))
|
||||||
|
.where(eq(assessments.id, assessmentId));
|
||||||
|
|
||||||
|
if (!queryResult.length)
|
||||||
|
throw new HTTPException(404, {
|
||||||
|
message: "The assessment does not exist",
|
||||||
|
});
|
||||||
|
|
||||||
|
const assessmentData = queryResult[0];
|
||||||
|
|
||||||
|
return c.json(assessmentData);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.patch(
|
||||||
|
"/:id",
|
||||||
|
checkPermission("assessmentRequestManagement.update"),
|
||||||
|
requestValidator(
|
||||||
|
"json",
|
||||||
|
z.object({
|
||||||
|
status: z.enum(["menunggu konfirmasi", "diterima", "ditolak", "selesai"]),
|
||||||
|
})
|
||||||
|
),
|
||||||
|
async (c) => {
|
||||||
|
const assessmentId = c.req.param("id");
|
||||||
|
const { status } = c.req.valid("json");
|
||||||
|
|
||||||
|
const assessment = await db
|
||||||
|
.select()
|
||||||
|
.from(assessments)
|
||||||
|
.where(and(eq(assessments.id, assessmentId),));
|
||||||
|
|
||||||
|
if (!assessment[0]) throw new HTTPException(404, {
|
||||||
|
message: "Assessment tidak ditemukan.",
|
||||||
|
});
|
||||||
|
|
||||||
|
await db
|
||||||
|
.update(assessments)
|
||||||
|
.set({
|
||||||
|
status,
|
||||||
|
})
|
||||||
|
.where(eq(assessments.id, assessmentId));
|
||||||
|
|
||||||
|
return c.json({
|
||||||
|
message: "Status assessment berhasil diperbarui.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default assessmentsRequestManagementRoutes;
|
||||||
Loading…
Reference in New Issue
Block a user