import { NextRequestWithAuth, withAuth } from "next-auth/middleware"; import { ability, authOptions } from "@/config/authConfig"; import { NextFetchEvent, NextResponse } from "next/server"; import { getToken } from "next-auth/jwt"; // user groups export const [ SUPER_ADMIN, TOP_MANAGEMENT, TEAM_LEAD, NORMAL_STAFF, SUPPORTING_STAFF ] = [ "Super Admin", "Top Management", "Team Leader", "Normal Staff", "Supporting Staff" ] // abilities export const [ MAINTAIN_USER, MAINTAIN_TIMESHEET, VIEW_TASK_TEMPLATE, VIEW_GROUP, VIEW_CLIENT, VIEW_SUBSIDIARY, VIEW_STAFF, VIEW_COMPANY, VIEW_SKILL, VIEW_DEPARTMENT, VIEW_POSITION, VIEW_SALARY, VIEW_TEAM, VIEW_HOLIDAY, VIEW_MAIL, MAINTAIN_CLIENT, MAINTAIN_SUBSIDIARY, MAINTAIN_STAFF, MAINTAIN_COMPANY, MAINTAIN_SKILL, MAINTAIN_DEPARTMENT, MAINTAIN_POSITION, MAINTAIN_SALARY, MAINTAIN_TEAM, MAINTAIN_GROUP, MAINTAIN_HOLIDAY, MAINTAIN_MAIL, VIEW_DASHBOARD_SELF, VIEW_DASHBOARD_ALL, IMPORT_INVOICE, VIEW_STAFF_PROFILE, IMPORT_RECEIPT, MAINTAIN_TASK_TEMPLATE, MAINTAIN_TIMESHEET_7DAYS, VIEW_PROJECT, MAINTAIN_PROJECT, DELETE_PROJECT, MAINTAIN_TIMESHEET_FAST_TIME_ENTRY, VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING, MAINTAIN_NORMAL_STAFF_WORKSPACE, MAINTAIN_MANAGEMENT_STAFF_WORKSPACE, GENERATE_LATE_START_REPORT, GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, GENERATE_COST_AND_EXPENSE_REPORT, GENERATE_PROJECT_COMPLETION_REPORT, GENERATE_PROJECT_PANDL_REPORT, GENERATE_FINANCIAL_STATUS_REPORT, GENERATE_PROJECT_CASH_FLOW_REPORT, GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, GENERATE_CROSS_TEAM_CHARGE_REPORT ] = [ 'MAINTAIN_USER', 'MAINTAIN_TIMESHEET', 'VIEW_TASK_TEMPLATE', 'VIEW_GROUP', 'VIEW_CLIENT', 'VIEW_SUBSIDIARY', 'VIEW_STAFF', 'VIEW_COMPANY', 'VIEW_SKILL', 'VIEW_DEPARTMENT', 'VIEW_POSITION', 'VIEW_SALARY', 'VIEW_TEAM', 'VIEW_HOLIDAY', 'VIEW_MAIL', 'MAINTAIN_CLIENT', 'MAINTAIN_SUBSIDIARY', 'MAINTAIN_STAFF', 'MAINTAIN_COMPANY', 'MAINTAIN_SKILL', 'MAINTAIN_DEPARTMENT', 'MAINTAIN_POSITION', 'MAINTAIN_SALARY', 'MAINTAIN_TEAM', 'MAINTAIN_GROUP', 'MAINTAIN_HOLIDAY', 'MAINTAIN_MAIL', 'VIEW_DASHBOARD_SELF', 'VIEW_DASHBOARD_ALL', 'IMPORT_INVOICE', 'VIEW_STAFF_PROFILE', 'IMPORT_RECEIPT', 'MAINTAIN_TASK_TEMPLATE', 'MAINTAIN_TIMESHEET_7DAYS', 'VIEW_PROJECT', 'MAINTAIN_PROJECT', 'DELETE_PROJECT', 'MAINTAIN_TIMESHEET_FAST_TIME_ENTRY', 'VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING', 'MAINTAIN_NORMAL_STAFF_WORKSPACE', 'MAINTAIN_MANAGEMENT_STAFF_WORKSPACE', 'G_LATE_START_REPORT', 'G_PROJECT_POTENTIAL_DELAY_REPORT', 'G_RESOURCE_OVERCONSUMPTION_REPORT', 'G_COST_AND_EXPENSE_REPORT', 'G_PROJECT_COMPLETION_REPORT', 'G_PROJECT_P&L_REPORT', 'G_FINANCIAL_STATUS_REPORT', 'G_PROJECT_CASH_FLOW_REPORT', 'G_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT', 'G_CROSS_TEAM_CHARGE_REPORT' ] const PRIVATE_ROUTES = [ "/analytics", "/dashboard", // "/home", "/invoice", "/projects", "/tasks", "/settings", "/staffReimbursement", ]; const LANG_QUERY_PARAM = "lang"; export default async function middleware( req: NextRequestWithAuth, event: NextFetchEvent, ) { const langPref = req.nextUrl.searchParams.get(LANG_QUERY_PARAM); // const token = await getToken({ req: req, secret: process.env.SECRET }); if (langPref) { // Redirect to same url without the lang query param + set cookies const newUrl = new URL(req.nextUrl); newUrl.searchParams.delete(LANG_QUERY_PARAM); const response = NextResponse.redirect(newUrl); response.cookies.set("i18next", langPref); return response; } const authMiddleware = withAuth({ pages: authOptions.pages, callbacks: { authorized: ({ req, token }) => { let isAuth = Boolean(token); if (!Boolean(token)) { return Boolean(token) } const abilities = (token!.abilities as ability[]).map((item: ability) => item.actionSubjectCombo); if (req.nextUrl.pathname.startsWith('/projects')) { isAuth = [MAINTAIN_PROJECT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/tasks')) { isAuth = [MAINTAIN_TASK_TEMPLATE].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings')) { isAuth = [ VIEW_CLIENT, VIEW_SUBSIDIARY, VIEW_STAFF, VIEW_COMPANY, VIEW_SKILL, VIEW_DEPARTMENT, VIEW_POSITION, VIEW_SALARY, VIEW_TEAM, VIEW_GROUP, VIEW_HOLIDAY, VIEW_MAIL, MAINTAIN_CLIENT, MAINTAIN_SUBSIDIARY, MAINTAIN_STAFF, MAINTAIN_COMPANY, MAINTAIN_SKILL, MAINTAIN_DEPARTMENT, MAINTAIN_POSITION, MAINTAIN_SALARY, MAINTAIN_TEAM, MAINTAIN_GROUP, MAINTAIN_HOLIDAY, MAINTAIN_MAIL ].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/customer/create') || req.nextUrl.pathname.startsWith('/settings/customer/edit')) { isAuth = [MAINTAIN_CLIENT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/subsidiary/create') || req.nextUrl.pathname.startsWith('/settings/subsidiary/edit')) { isAuth = [MAINTAIN_SUBSIDIARY].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/staff/create') || req.nextUrl.pathname.startsWith('/settings/staff/edit')) { isAuth = [MAINTAIN_STAFF].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/company/create') || req.nextUrl.pathname.startsWith('/settings/company/edit')) { isAuth = [MAINTAIN_COMPANY].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/skill/create') || req.nextUrl.pathname.startsWith('/settings/skill/edit')) { isAuth = [MAINTAIN_SKILL].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/department/create') || req.nextUrl.pathname.startsWith('/settings/department/edit')) { isAuth = [MAINTAIN_DEPARTMENT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/position/create') || req.nextUrl.pathname.startsWith('/settings/position/edit')) { isAuth = [MAINTAIN_POSITION].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/team/create') || req.nextUrl.pathname.startsWith('/settings/team/edit')) { isAuth = [MAINTAIN_TEAM].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/group/create') || req.nextUrl.pathname.startsWith('/settings/group/edit')) { isAuth = [MAINTAIN_GROUP].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/holiday/create') || req.nextUrl.pathname.startsWith('/settings/holiday/edit')) { isAuth = [MAINTAIN_HOLIDAY].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/user')) { isAuth = [MAINTAIN_USER].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/staff/user')) { isAuth = [MAINTAIN_USER].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics')) { isAuth = [ GENERATE_LATE_START_REPORT, GENERATE_PROJECT_POTENTIAL_DELAY_REPORT, GENERATE_RESOURCE_OVERCONSUMPTION_REPORT, GENERATE_COST_AND_EXPENSE_REPORT, GENERATE_PROJECT_COMPLETION_REPORT, GENERATE_PROJECT_PANDL_REPORT, GENERATE_FINANCIAL_STATUS_REPORT, GENERATE_PROJECT_CASH_FLOW_REPORT, GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT, GENERATE_CROSS_TEAM_CHARGE_REPORT ].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/LateStartReport')) { isAuth = [GENERATE_LATE_START_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/ProjectPotentialDelayReport')) { isAuth = [GENERATE_PROJECT_POTENTIAL_DELAY_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/ResourceOverconsumptionReport')) { isAuth = [GENERATE_RESOURCE_OVERCONSUMPTION_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/CostandExpenseReport')) { isAuth = [GENERATE_COST_AND_EXPENSE_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/ProjectCompletionReport')) { isAuth = [GENERATE_PROJECT_COMPLETION_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/ProjectPandLReport')) { isAuth = [GENERATE_PROJECT_PANDL_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/FinancialStatusReport')) { isAuth = [GENERATE_FINANCIAL_STATUS_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/ProjectCashFlowReport')) { isAuth = [GENERATE_PROJECT_CASH_FLOW_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/StaffMonthlyWorkHoursAnalysisReport')) { isAuth = [GENERATE_STAFF_MONTHLY_WORK_HOURS_ANALYSIS_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/analytics/CrossTeamChargeReport')) { isAuth = [GENERATE_CROSS_TEAM_CHARGE_REPORT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/settings/staff/edit')) { isAuth = [VIEW_STAFF_PROFILE].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/invoice')) { isAuth = [IMPORT_INVOICE, IMPORT_RECEIPT].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/dashboard')) { isAuth = [VIEW_DASHBOARD_ALL, VIEW_DASHBOARD_SELF].some((ability) => abilities.includes(ability)); } if (req.nextUrl.pathname.startsWith('/dashboard/ProjectResourceConsumptionRanking')) { isAuth = [VIEW_PROJECT_RESOURCE_CONSUMPTION_RANKING].some((ability) => abilities.includes(ability)); } return isAuth } } }); // Matcher for using the auth middleware return PRIVATE_ROUTES.some((route) => req.nextUrl.pathname.startsWith(route)) ? await authMiddleware(req, event) // Let auth middleware handle response : NextResponse.next(); // Return normal response }