diff --git a/apps/web/app/api/timesheet/activity/report/route.ts b/apps/web/app/api/timesheet/activity/report/route.ts index 63b75d4ca2..c10893b07a 100644 --- a/apps/web/app/api/timesheet/activity/report/route.ts +++ b/apps/web/app/api/timesheet/activity/report/route.ts @@ -1,4 +1,5 @@ -import { NextRequest } from 'next/server'; +import { NextRequest, NextResponse } from 'next/server'; +import { authenticatedGuard } from '@/core/services/server/guards/authenticated-guard-app'; import { getActivityReportRequest } from '@/core/services/server/requests/timesheet'; import { IActivityRequestParams } from '@/core/services/server/requests/timesheet'; import { ETimeLogType } from '@/core/types/generics/enums/timer'; @@ -11,7 +12,15 @@ export const runtime = 'nodejs'; * Fetches activity report data based on provided query parameters */ export async function GET(req: NextRequest) { + const res = new NextResponse(); + try { + // Authenticate before reading parameters: the guard answers 401 to a rejected token and 503 when + // the session check could not reach Gauzy, so an outage never looks like an expired session + const guard = await authenticatedGuard(req, res); + if (!guard.user) return guard.deny(); + const { access_token } = guard; + const searchParams = req.nextUrl.searchParams; const params: Partial = { @@ -63,7 +72,7 @@ export async function GET(req: NextRequest) { } // Fetch activity report data - const data = await getActivityReportRequest(params as IActivityRequestParams); + const { data } = await getActivityReportRequest(params as IActivityRequestParams, access_token); return new Response(JSON.stringify(data), { status: 200, diff --git a/apps/web/app/api/timesheet/time-log/report/daily/route.ts b/apps/web/app/api/timesheet/time-log/report/daily/route.ts index 48c4f996c1..50be2be29e 100644 --- a/apps/web/app/api/timesheet/time-log/report/daily/route.ts +++ b/apps/web/app/api/timesheet/time-log/report/daily/route.ts @@ -1,4 +1,5 @@ -import { NextRequest } from 'next/server'; +import { NextRequest, NextResponse } from 'next/server'; +import { authenticatedGuard } from '@/core/services/server/guards/authenticated-guard-app'; import { getTimeLogReportDailyRequest } from '@/core/services/server/requests/timesheet'; import { ITimeLogRequestParams } from '@/core/services/server/requests/timesheet'; @@ -6,7 +7,15 @@ export const dynamic = 'force-dynamic'; export const runtime = 'nodejs'; export async function GET(req: NextRequest) { + const res = new NextResponse(); + try { + // Authenticate before reading parameters: the guard answers 401 to a rejected token and 503 when + // the session check could not reach Gauzy, so an outage never looks like an expired session + const guard = await authenticatedGuard(req, res); + if (!guard.user) return guard.deny(); + const { access_token } = guard; + const searchParams = req.nextUrl.searchParams; const params: Partial = { @@ -53,9 +62,9 @@ export async function GET(req: NextRequest) { }; } - const response = await getTimeLogReportDailyRequest(params as ITimeLogRequestParams); + const { data } = await getTimeLogReportDailyRequest(params as ITimeLogRequestParams, access_token); - return new Response(JSON.stringify(response), { + return new Response(JSON.stringify(data), { status: 200, headers: { 'Content-Type': 'application/json' diff --git a/apps/web/core/services/server/guards/authenticated-guard-app.ts b/apps/web/core/services/server/guards/authenticated-guard-app.ts index 574003b4e2..d168f0974b 100644 --- a/apps/web/core/services/server/guards/authenticated-guard-app.ts +++ b/apps/web/core/services/server/guards/authenticated-guard-app.ts @@ -17,14 +17,37 @@ export async function authenticatedGuard(req: Request, res: NextResponse { + const reason = error instanceof Promise ? await error.catch((data) => data) : error; + rejection = reason && typeof reason === 'object' ? reason : undefined; + console.error(reason); + }); if (!r_res || (r_res.data as any).statusCode === 401) { + // Keep Gauzy's own status (401, 404, 429...); only a check that never got an answer is a 503, so + // an outage never looks like an expired session that the client should log out. + const upstream: { statusCode?: number; message?: string } | undefined = rejection ?? (r_res?.data as any); + const status = + typeof upstream?.statusCode === 'number' && upstream.statusCode >= 400 ? upstream.statusCode : 503; return { $res: (data: any) => NextResponse.json({ statusCode: 401, message: data }), - user: null + user: null, + status, + deny: () => + NextResponse.json( + { + message: + status === 503 + ? 'Session check unavailable, retry later' + : upstream?.message || 'Unauthorized' + }, + { status } + ) }; }