const express = require('express'); const { certificateController } = require('../modules/certificate'); const { verifyJWT } = require('../middleware/verifyJWT'); const isAdmin = require('../middleware/isAdmin'); const isMentorOrAdmin = require('../middleware/isMentorOrAdmin'); const multer = require('../middleware/multer'); const { multerErrorHandler, checkFileSizes } = require('../middleware/multer'); const router = express.Router(); /** * @swagger * components: * schemas: * Certificate: * type: object * properties: * id: * type: integer * example: 1 * id_project: * type: integer * example: 2 * id_user: * type: integer * example: 5 * certificate_no: * type: string * example: "CERT/20260609/PRJ2/USR5" * issued_at: * type: string * format: date-time * example: "2026-06-09T14:00:00.000Z" * user: * type: object * properties: * id: * type: integer * example: 5 * full_name: * type: string * example: "Rafi Athallah" * email: * type: string * example: "rafi@student.com" * project: * type: object * properties: * id: * type: integer * example: 2 * project_name: * type: string * example: "Internify Platform Dev" * description: * type: string * example: "Project to develop features of the Internify web app" * start_date: * type: string * format: date * example: "2026-07-10" * end_date: * type: string * format: date * example: "2026-08-10" * CertificateClaimRequest: * type: object * required: * - id_project * properties: * id_project: * type: integer * example: 2 */ /** * @swagger * /certificate-api/claim: * post: * summary: Claim certificate for a completed project * description: Interns can claim a certificate for a project once they have submitted all assigned tasks. * tags: [Certificate] * security: * - bearerAuth: [] * requestBody: * required: true * content: * application/json: * schema: * $ref: '#/components/schemas/CertificateClaimRequest' * responses: * 201: * description: Certificate claimed successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * $ref: '#/components/schemas/Certificate' * message: * type: string * example: "Certificate claimed successfully" * code: * type: integer * example: 201 * 400: * description: Bad request (no tasks assigned or not all tasks submitted) * 401: * description: Unauthorized * 403: * description: Forbidden (only interns can claim, or not a member of project) * 404: * description: Project not found * 409: * description: Conflict (certificate already claimed) * 500: * description: Internal server error */ router.post('/claim', verifyJWT, certificateController.claimCertificate); /** * @swagger * /certificate-api/generate: * post: * summary: Batch generate certificates (Admin/Mentor only) * description: Mentors or Admins can batch-generate certificates for selected eligible interns of a project. * tags: [Certificate] * security: * - bearerAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - id_project * - id_users * properties: * id_project: * type: integer * example: 2 * id_users: * type: array * items: * type: integer * example: [5, 6] * responses: * 201: * description: Certificates generated successfully * 400: * description: Bad request (not eligible or missing parameters) * 401: * description: Unauthorized * 403: * description: Forbidden (only mentors/admins of the project can generate) * 409: * description: Conflict (certificate already generated for one or more interns) * 500: * description: Internal server error */ router.post('/generate', verifyJWT, isMentorOrAdmin, certificateController.generateCertificates); /** * @swagger * /certificate-api/my-certificates: * get: * summary: Get logged-in intern's certificates * description: Retrieve all certificates earned by the currently logged-in intern. * tags: [Certificate] * security: * - bearerAuth: [] * responses: * 200: * description: Certificates retrieved successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Certificate' * message: * type: string * example: "Certificates retrieved successfully" * code: * type: integer * example: 200 * 401: * description: Unauthorized * 403: * description: Forbidden (only interns can access this) * 500: * description: Internal server error */ router.get('/my-certificates', verifyJWT, certificateController.getMyCertificates); /** * @swagger * /certificate-api/all: * get: * summary: Get all issued certificates (Admin only) * description: Admin/Mentor can retrieve all certificates issued across the system. * tags: [Certificate] * security: * - bearerAuth: [] * responses: * 200: * description: All certificates retrieved successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Certificate' * message: * type: string * example: "All certificates retrieved successfully" * code: * type: integer * example: 200 * 401: * description: Unauthorized * 403: * description: Forbidden (Admin only) * 500: * description: Internal server error */ router.get('/all', verifyJWT, isAdmin, certificateController.getAllCertificates); /** * @swagger * /certificate-api/detail/{id}: * get: * summary: Get certificate detail * description: Fetch detailed information for a certificate by its ID. Interns can only access their own. Admins can access any. * tags: [Certificate] * security: * - bearerAuth: [] * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: Certificate ID * example: 1 * responses: * 200: * description: Certificate details retrieved successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * $ref: '#/components/schemas/Certificate' * message: * type: string * example: "Certificate details retrieved successfully" * code: * type: integer * example: 200 * 401: * description: Unauthorized * 403: * description: Forbidden (Accessing another user's certificate) * 404: * description: Certificate not found * 500: * description: Internal server error */ router.get('/detail/:id', verifyJWT, certificateController.getCertificateDetail); /** * @swagger * /certificate-api/project/{id_project}: * get: * summary: Get certificates issued for a specific project (Admin/Mentor only) * description: Admin/Mentor can retrieve all certificates issued to interns for a specific project. * tags: [Certificate] * security: * - bearerAuth: [] * parameters: * - in: path * name: id_project * schema: * type: integer * required: true * description: Project ID * example: 2 * responses: * 200: * description: Project certificates retrieved successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * type: array * items: * $ref: '#/components/schemas/Certificate' * message: * type: string * example: "Project certificates retrieved successfully" * code: * type: integer * example: 200 * 401: * description: Unauthorized * 403: * description: Forbidden (Admin/Mentor only) * 500: * description: Internal server error */ router.get('/project/:id_project', verifyJWT, isMentorOrAdmin, certificateController.getProjectCertificates); /** * @swagger * /certificate-api/verify-uuid/{uuid}: * get: * summary: Verify a certificate by UUID (Public) * description: Verify the validity of a certificate by its unique UUID for the frontend. Returns intern's name, creation date, and UUID. * tags: [Certificate] * parameters: * - in: path * name: uuid * schema: * type: string * format: uuid * required: true * description: The certificate UUID to verify * example: "f81d4fae-7dec-11d0-a765-00a0c91e6bf6" * responses: * 200: * description: Certificate is valid * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * type: object * properties: * uuid: * type: string * example: "f81d4fae-7dec-11d0-a765-00a0c91e6bf6" * intern_name: * type: string * example: "Rafi Athallah" * project: * type: object * properties: * id: * type: integer * example: 2 * project_name: * type: string * example: "Internify Platform Dev" * description: * type: string * example: "Project to develop features of the Internify web app" * start_date: * type: string * format: date * example: "2026-07-10" * end_date: * type: string * format: date * example: "2026-08-10" * created_at: * type: string * format: date-time * example: "2026-06-09T14:00:00.000Z" * message: * type: string * example: "Certificate validated successfully" * code: * type: integer * example: 200 * 400: * description: Bad request (missing UUID) * 404: * description: Certificate not found or invalid * 500: * description: Internal server error */ router.get('/verify-uuid/:uuid', certificateController.verifyCertificateByUuid); /** * @swagger * /certificate-api/projects/{id_project}/template: * post: * summary: Upload certificate template for a project * description: Admin or Mentor can upload a certificate template file (image/pdf) for a specific project. Mentors can only upload to projects they own. * tags: [Certificate] * security: * - bearerAuth: [] * parameters: * - in: path * name: id_project * schema: * type: integer * required: true * description: The ID of the project to associate the template with * example: 1 * requestBody: * required: true * content: * multipart/form-data: * schema: * type: object * required: * - template * properties: * template: * type: string * format: binary * description: The certificate template file (JPEG, JPG, PNG, or PDF). Max size 5MB. * responses: * 200: * description: Certificate template uploaded successfully * content: * application/json: * schema: * type: object * properties: * status: * type: boolean * example: true * data: * type: object * properties: * id_project: * type: integer * example: 1 * certificate_template: * type: string * example: "/uploads/1718000000000-987654321.png" * message: * type: string * example: "Certificate template uploaded successfully" * code: * type: integer * example: 200 * 400: * description: Bad request (missing file or invalid input) * 401: * description: Unauthorized * 403: * description: Forbidden (Mentor does not own the project, or unauthorized role) * 404: * description: Project not found * 413: * description: File size too large (max 5MB) * 500: * description: Internal server error */ router.post( '/projects/:id_project/template', verifyJWT, isMentorOrAdmin, multer.single('template'), checkFileSizes, multerErrorHandler, certificateController.uploadCertificateTemplate ); module.exports = router;