(Feat-Fix): New Activity Creation system, fixed activities being hardcoded and not displaying properly in the dropdown, added dynamic subdepartment activity fetching.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Router } from "@oak/oak";
|
||||
import { db } from "../config/database.ts";
|
||||
import { authenticateToken } from "../middleware/auth.ts";
|
||||
import { authenticateToken, getCurrentUser } from "../middleware/auth.ts";
|
||||
|
||||
const router = new Router();
|
||||
|
||||
@@ -86,9 +86,10 @@ router.get("/:id", authenticateToken, async (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Create activity (SuperAdmin only)
|
||||
// Create activity (SuperAdmin or Supervisor for their own department)
|
||||
router.post("/", authenticateToken, async (ctx) => {
|
||||
try {
|
||||
const user = getCurrentUser(ctx);
|
||||
const body = await ctx.request.body.json();
|
||||
const { sub_department_id, name, unit_of_measurement } = body;
|
||||
|
||||
@@ -98,6 +99,33 @@ router.post("/", authenticateToken, async (ctx) => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the sub-department to check department ownership
|
||||
const subDepts = await db.query<{ department_id: number }[]>(
|
||||
"SELECT department_id FROM sub_departments WHERE id = ?",
|
||||
[sub_department_id]
|
||||
);
|
||||
|
||||
if (subDepts.length === 0) {
|
||||
ctx.response.status = 404;
|
||||
ctx.response.body = { error: "Sub-department not found" };
|
||||
return;
|
||||
}
|
||||
|
||||
const subDeptDepartmentId = subDepts[0].department_id;
|
||||
|
||||
// Check authorization
|
||||
if (user.role === 'Supervisor' && user.departmentId !== subDeptDepartmentId) {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "You can only create activities for your own department" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.role !== 'SuperAdmin' && user.role !== 'Supervisor') {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "Unauthorized" };
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await db.execute(
|
||||
"INSERT INTO activities (sub_department_id, name, unit_of_measurement) VALUES (?, ?, ?)",
|
||||
[sub_department_id, name, unit_of_measurement || "Per Bag"]
|
||||
@@ -109,6 +137,12 @@ router.post("/", authenticateToken, async (ctx) => {
|
||||
message: "Activity created successfully"
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as { code?: string };
|
||||
if (err.code === "ER_DUP_ENTRY") {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "Activity already exists in this sub-department" };
|
||||
return;
|
||||
}
|
||||
console.error("Create activity error:", error);
|
||||
ctx.response.status = 500;
|
||||
ctx.response.body = { error: "Internal server error" };
|
||||
@@ -135,11 +169,42 @@ router.put("/:id", authenticateToken, async (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Delete activity
|
||||
// Delete activity (SuperAdmin or Supervisor for their own department)
|
||||
router.delete("/:id", authenticateToken, async (ctx) => {
|
||||
try {
|
||||
const user = getCurrentUser(ctx);
|
||||
const activityId = ctx.params.id;
|
||||
|
||||
// Get the activity and its sub-department to check department ownership
|
||||
const activities = await db.query<Activity[]>(
|
||||
`SELECT a.*, sd.department_id
|
||||
FROM activities a
|
||||
JOIN sub_departments sd ON a.sub_department_id = sd.id
|
||||
WHERE a.id = ?`,
|
||||
[activityId]
|
||||
);
|
||||
|
||||
if (activities.length === 0) {
|
||||
ctx.response.status = 404;
|
||||
ctx.response.body = { error: "Activity not found" };
|
||||
return;
|
||||
}
|
||||
|
||||
const activity = activities[0] as Activity & { department_id: number };
|
||||
|
||||
// Check authorization
|
||||
if (user.role === 'Supervisor' && user.departmentId !== activity.department_id) {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "You can only delete activities from your own department" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.role !== 'SuperAdmin' && user.role !== 'Supervisor') {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "Unauthorized" };
|
||||
return;
|
||||
}
|
||||
|
||||
await db.execute("DELETE FROM activities WHERE id = ?", [activityId]);
|
||||
|
||||
ctx.response.body = { message: "Activity deleted successfully" };
|
||||
|
||||
@@ -101,35 +101,140 @@ router.post("/", authenticateToken, authorize("SuperAdmin"), async (ctx) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Create sub-department (SuperAdmin only)
|
||||
router.post("/:id/sub-departments", authenticateToken, authorize("SuperAdmin"), async (ctx) => {
|
||||
// Create sub-department (SuperAdmin or Supervisor for their own department)
|
||||
router.post("/sub-departments", authenticateToken, async (ctx) => {
|
||||
try {
|
||||
const deptId = ctx.params.id;
|
||||
const body = await ctx.request.body.json() as { name: string; primaryActivity: string };
|
||||
const { name, primaryActivity } = body;
|
||||
const user = getCurrentUser(ctx);
|
||||
const body = await ctx.request.body.json() as { department_id: number; name: string };
|
||||
const { department_id, name } = body;
|
||||
|
||||
if (!name || !primaryActivity) {
|
||||
if (!name || !department_id) {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "Name and primary activity required" };
|
||||
ctx.response.body = { error: "Department ID and name are required" };
|
||||
return;
|
||||
}
|
||||
|
||||
// Check authorization
|
||||
if (user.role === 'Supervisor' && user.departmentId !== department_id) {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "You can only create sub-departments for your own department" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.role !== 'SuperAdmin' && user.role !== 'Supervisor') {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "Unauthorized" };
|
||||
return;
|
||||
}
|
||||
|
||||
const sanitizedName = sanitizeInput(name);
|
||||
const sanitizedActivity = sanitizeInput(primaryActivity);
|
||||
|
||||
const result = await db.execute(
|
||||
"INSERT INTO sub_departments (department_id, name, primary_activity) VALUES (?, ?, ?)",
|
||||
[deptId, sanitizedName, sanitizedActivity]
|
||||
"INSERT INTO sub_departments (department_id, name) VALUES (?, ?)",
|
||||
[department_id, sanitizedName]
|
||||
);
|
||||
|
||||
const newSubDepartment = await db.query<SubDepartment[]>(
|
||||
"SELECT * FROM sub_departments WHERE id = ?",
|
||||
[result.insertId]
|
||||
[result.lastInsertId]
|
||||
);
|
||||
|
||||
ctx.response.status = 201;
|
||||
ctx.response.body = newSubDepartment[0];
|
||||
} catch (error) {
|
||||
const err = error as { code?: string };
|
||||
if (err.code === "ER_DUP_ENTRY") {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "Sub-department already exists in this department" };
|
||||
return;
|
||||
}
|
||||
console.error("Create sub-department error:", error);
|
||||
ctx.response.status = 500;
|
||||
ctx.response.body = { error: "Internal server error" };
|
||||
}
|
||||
});
|
||||
|
||||
// Delete sub-department (SuperAdmin or Supervisor for their own department)
|
||||
router.delete("/sub-departments/:id", authenticateToken, async (ctx) => {
|
||||
try {
|
||||
const user = getCurrentUser(ctx);
|
||||
const subDeptId = ctx.params.id;
|
||||
|
||||
// Get the sub-department to check department ownership
|
||||
const subDepts = await db.query<SubDepartment[]>(
|
||||
"SELECT * FROM sub_departments WHERE id = ?",
|
||||
[subDeptId]
|
||||
);
|
||||
|
||||
if (subDepts.length === 0) {
|
||||
ctx.response.status = 404;
|
||||
ctx.response.body = { error: "Sub-department not found" };
|
||||
return;
|
||||
}
|
||||
|
||||
const subDept = subDepts[0];
|
||||
|
||||
// Check authorization
|
||||
if (user.role === 'Supervisor' && user.departmentId !== subDept.department_id) {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "You can only delete sub-departments from your own department" };
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.role !== 'SuperAdmin' && user.role !== 'Supervisor') {
|
||||
ctx.response.status = 403;
|
||||
ctx.response.body = { error: "Unauthorized" };
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete associated activities first (cascade should handle this, but being explicit)
|
||||
await db.execute("DELETE FROM activities WHERE sub_department_id = ?", [subDeptId]);
|
||||
|
||||
// Delete the sub-department
|
||||
await db.execute("DELETE FROM sub_departments WHERE id = ?", [subDeptId]);
|
||||
|
||||
ctx.response.body = { message: "Sub-department deleted successfully" };
|
||||
} catch (error) {
|
||||
console.error("Delete sub-department error:", error);
|
||||
ctx.response.status = 500;
|
||||
ctx.response.body = { error: "Internal server error" };
|
||||
}
|
||||
});
|
||||
|
||||
// Legacy route for creating sub-department under specific department (SuperAdmin only)
|
||||
router.post("/:id/sub-departments", authenticateToken, authorize("SuperAdmin"), async (ctx) => {
|
||||
try {
|
||||
const deptId = ctx.params.id;
|
||||
const body = await ctx.request.body.json() as { name: string };
|
||||
const { name } = body;
|
||||
|
||||
if (!name) {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "Name is required" };
|
||||
return;
|
||||
}
|
||||
|
||||
const sanitizedName = sanitizeInput(name);
|
||||
|
||||
const result = await db.execute(
|
||||
"INSERT INTO sub_departments (department_id, name) VALUES (?, ?)",
|
||||
[deptId, sanitizedName]
|
||||
);
|
||||
|
||||
const newSubDepartment = await db.query<SubDepartment[]>(
|
||||
"SELECT * FROM sub_departments WHERE id = ?",
|
||||
[result.lastInsertId]
|
||||
);
|
||||
|
||||
ctx.response.status = 201;
|
||||
ctx.response.body = newSubDepartment[0];
|
||||
} catch (error) {
|
||||
const err = error as { code?: string };
|
||||
if (err.code === "ER_DUP_ENTRY") {
|
||||
ctx.response.status = 400;
|
||||
ctx.response.body = { error: "Sub-department already exists in this department" };
|
||||
return;
|
||||
}
|
||||
console.error("Create sub-department error:", error);
|
||||
ctx.response.status = 500;
|
||||
ctx.response.body = { error: "Internal server error" };
|
||||
|
||||
Reference in New Issue
Block a user