Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/backend/lambdas/reports/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ TODO: Add a description of the reports lambda.
| GET | /reports | |
| GET | /reports/upload-url | |
| POST | /reports | |
| GET | /reports/{id} | |
| DELETE | /reports/{id} | |

## Setup

Expand Down
71 changes: 70 additions & 1 deletion apps/backend/lambdas/reports/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,76 @@ export const handler = async (event: any): Promise<APIGatewayProxyResult> => {

return json(201, report);
}
// <<< ROUTES-END

// GET /reports/{id}
if ((/^\/reports\/\d+$/.test(normalizedPath) || /^\/\d+$/.test(normalizedPath)) && method === 'GET') { const id = normalizedPath.split('/').pop() as string;

if (!/^\d+$/.test(id)) {
return json(400, { message: 'id must be a positive integer' });
}

const authContext = await authenticateRequest(event);
if (!authContext.isAuthenticated || !authContext.user) {
return json(401, { message: 'Authentication required' });
}

const { user } = authContext;

const report = await db.selectFrom('branch.reports').where('report_id', '=', Number(id)).selectAll().executeTakeFirst();
if (!report) return json(404, { message: 'Report not found' });

const hasAccess = await checkProjectAccess(user.userId!, report.project_id, user.isAdmin);
if (!hasAccess) {
return json(403, { message: 'You do not have access to this report' });
}

return json(200, {
ok: true,
route: 'GET /reports/{id}',
pathParams: { id },
body: {
report_id: report.report_id,
project_id: report.project_id,
title: report.title,
object_url: report.object_url,
report_type: report.report_type,
date_created: report.date_created,
}
});
}

// DELETE /reports/{id}
if ((/^\/reports\/\d+$/.test(normalizedPath) || /^\/\d+$/.test(normalizedPath)) && method === 'DELETE') {
const id = normalizedPath.split('/').pop() as string;

if (!/^\d+$/.test(id)) {
return json(400, { message: 'id must be a positive integer' });
}


const authContext = await authenticateRequest(event);
if (!authContext.isAuthenticated || !authContext.user) {
return json(401, { message: 'Authentication required' });
}

const { user } = authContext;

const report = await db.selectFrom('branch.reports').where('report_id', '=', Number(id)).selectAll().executeTakeFirst();
if (!report) return json(404, { message: 'Report not found' });

const hasAccess = await checkProjectAccess(user.userId!, report.project_id, user.isAdmin);
if (!hasAccess) {
return json(403, { message: 'You do not have access to delete this report' });
}

const deleted = await db.deleteFrom('branch.reports').where('report_id', '=', Number(id)).execute();
if (!deleted[0] || deleted[0].numDeletedRows === 0n) {
return json(404, { message: 'Report not found' });
}

return json(200, { ok: true, route: 'DELETE /reports/{id}', pathParams: { id } });
}
// <<< ROUTES-END

return json(404, { message: 'Not Found', path: normalizedPath, method });
} catch (err) {
Expand Down
28 changes: 26 additions & 2 deletions apps/backend/lambdas/reports/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ paths:

/reports:
get:
summary: GET /reports paginated list
summary: GET /reports paginated list
parameters:
- in: query
name: page
Expand Down Expand Up @@ -86,7 +86,7 @@ paths:
'401':
description: Unauthorized
post:
summary: POST /reports save a manually uploaded report
summary: POST /reports save a manually uploaded report
description: >
Creates a report record using the S3 object URL obtained from
GET /reports/upload-url after the client has uploaded the file directly
Expand Down Expand Up @@ -214,6 +214,30 @@ paths:
'500':
description: Internal server error

/reports/{id}:
get:
summary: GET /reports/{id}
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: OK
delete:
summary: DELETE /reports/{id}
parameters:
- in: path
name: id
required: true
schema:
type: string
responses:
'200':
description: OK

components:
securitySchemes:
BearerAuth:
Expand Down
Loading
Loading