MaternAlert / src /facilities /facilities.controller.ts
Auspicious14's picture
fix(facilities): secure facility get endpoints
0fef56a
Raw
History Blame Contribute Delete
4.54 kB
import {
Body,
Controller,
Delete,
ForbiddenException,
Get,
Param,
Patch,
Post,
Query,
Req,
SetMetadata,
UseGuards,
} from "@nestjs/common";
import { FacilitiesService } from "./facilities.service";
// import { JwtAuthGuard } from "../auth/guards/jwt-auth.guard";
import { RolesGuard } from "../auth/guards/roles.guard";
import { JwtAuthGuard } from "src/auth/guards/jwt-auth.guard";
const Roles = (...roles: string[]) => SetMetadata("roles", roles);
@UseGuards(JwtAuthGuard, RolesGuard)
@Controller("facilities")
export class FacilitiesController {
constructor(private readonly facilitiesService: FacilitiesService) {}
// ─── FACILITY CRUD (SUPER_ADMIN only) ────────────────────────────────────
/** POST /facilities */
@Roles("SUPER_ADMIN")
@Post()
create(
@Body()
body: {
organizationId?: string;
name: string;
address?: string;
phone?: string;
adminFirstName: string;
adminLastName: string;
adminEmail: string;
adminPhone?: string;
adminType?: string;
},
) {
return this.facilitiesService.create(body);
}
/** GET /facilities */
@Roles("SUPER_ADMIN", "FACILITY_ADMIN", "FACILITY_STAFF")
@Get()
findAll() {
return this.facilitiesService.findAll();
}
/** GET /facilities/:id */
@Roles("SUPER_ADMIN", "FACILITY_ADMIN", "FACILITY_STAFF")
@Get(":id")
findOne(@Param("id") id: string, @Req() req: any) {
const requesterRole = req.user?.role;
const requesterFacilityId = req.user?.healthcareWorker?.facilityId;
// Only SUPER_ADMIN can access any facility, others can only access their own
if (requesterRole !== "SUPER_ADMIN" && requesterFacilityId !== id) {
throw new ForbiddenException("You are not authorized to access this facility");
}
return this.facilitiesService.findOne(id);
}
/** PATCH /facilities/:id */
@Roles("SUPER_ADMIN")
@Patch(":id")
update(
@Param("id") id: string,
@Body()
body: {
organizationId?: string | null;
name?: string;
address?: string;
phone?: string;
isActive?: boolean;
},
) {
return this.facilitiesService.update(id, body);
}
/** PATCH /facilities/:id/deactivate */
@Roles("SUPER_ADMIN")
@Patch(":id/deactivate")
deactivate(@Param("id") id: string) {
return this.facilitiesService.deactivate(id);
}
// ─── QR FACILITY LINKING ─────────────────────────────────────────────────
/**
* Health worker generates a QR token for their facility.
* Dashboard calls this then renders the token as a QR code.
*
* POST /facilities/generate-link-token
* Auth: HEALTH_WORKER
* Body: { healthWorkerId: string } ← replace with req.user in prod
*/
@Roles("FACILITY_ADMIN", "FACILITY_STAFF")
@Post("generate-link-token")
generateLinkToken(
@Req() req: any,
@Body() body: { healthWorkerId?: string },
) {
// In production: const healthWorkerId = req.user.healthcareWorkerId
const healthWorkerId = req.user?.healthcareWorkerId ?? body.healthWorkerId;
return this.facilitiesService.generateLinkToken(healthWorkerId);
}
/**
* Patient app calls this after scanning the QR code.
*
* POST /facilities/link-via-qr
* Auth: PATIENT
* Body: { token: string }
*/
@Roles("PATIENT")
@Post("link-via-qr")
linkViaQR(@Req() req: any, @Body() body: { token: string; userId?: string }) {
// In production: const userId = req.user.id
const userId = req.user?.id ?? body.userId;
return this.facilitiesService.linkPatientViaQR(userId, body.token);
}
/**
* Get patient's current facility link status.
*
* GET /facilities/link-status
* Auth: PATIENT
*/
@Roles("PATIENT")
@Get("link-status")
getLinkStatus(@Req() req: any, @Query("userId") userId?: string) {
// In production: const userId = req.user.id
const id = req.user?.id ?? userId;
return this.facilitiesService.getLinkStatus(id);
}
/**
* Unlink patient from their current facility.
*
* DELETE /facilities/unlink
* Auth: PATIENT
*/
@Roles("PATIENT")
@Delete("unlink")
unlinkPatient(@Req() req: any, @Body() body: { userId?: string }) {
// In production: const userId = req.user.id
const userId = req.user?.id ?? body.userId;
return this.facilitiesService.unlinkPatient(userId);
}
}