From 34a104ea1f0205dfd5348df7dbedbbfc3d5d3bf9 Mon Sep 17 00:00:00 2001 From: samrth07 Date: Thu, 24 Jul 2025 20:39:19 +0530 Subject: [PATCH 1/7] final touch --- src/controllers/project.controller.ts | 4 ++-- src/routes/topics.ts | 19 ++++++++----------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/controllers/project.controller.ts b/src/controllers/project.controller.ts index b681207..fa0242c 100644 --- a/src/controllers/project.controller.ts +++ b/src/controllers/project.controller.ts @@ -43,7 +43,7 @@ export const createProject = async (req: Request, res: Response) => { name: req.body.projectData.name, imageUrl: imageUrl, githubUrl: req.body.projectData.githubUrl, - deployUrl: req.body.deployUrl, + deployUrl: req.body.projectData.deployUrl, AdminId: req.body.projectData.adminId, }; @@ -62,7 +62,7 @@ export const updateProjects = async (req: Request, res: Response) => { let imageUrl = null; const file = req.file; - if (file) { + if ( file ) { imageUrl = await uploadImage(supabase, file, 'projects'); } diff --git a/src/routes/topics.ts b/src/routes/topics.ts index ca52270..55bfcb6 100644 --- a/src/routes/topics.ts +++ b/src/routes/topics.ts @@ -40,17 +40,14 @@ export default function topicRouter() { * @apiBody {String} description description of the topic. * @apiBody {String} adminId ID of the admin creating the topic. * - * @apiSuccess {Object[]} questions List of questions inside the topic. - * @apiSuccess {Object} questions[].question Question object. - * @apiSuccess {Number} questions[].question.id Question ID. - * @apiSuccess {String} questions[].question.questionName Name of the question. - * @apiSuccess {String} questions[].question.link Link to the question. - * @apiSuccess {String="Easy","Medium","Hard"} questions[].question.difficulty Difficulty level of the question. - * @apiSuccess {Number} questions[].question.topicId Topic ID associated with the question. - * @apiSuccess {Number} questions[].question.createdAt Timestamp when the question was created (Unix timestamp). - * @apiSuccess {Number} questions[].question.updatedAt Timestamp when the question was last updated (Unix timestamp). - * @apiSuccess {String} questions[].question.createdById ID of the user who created the question. - * @apiSuccess {String} questions[].question.updatedById ID of the user who last updated the question. + * @apiSuccess {Object} Topic New Topic object. + * @apiSuccess {Number} Topic.id Topic ID. + * @apiSuccess {String} Topic.title Title of the topic. + * @apiSuccess {String} Topic.description Description of the topic. + * @apiSuccess {number} Topic.createdAt Timestamp when the topic was created. + * @apiSuccess {number} Topic.updatedAt Timestamp when the topic was last updated. + * @apiSuccess {String} Topic.createdById ID of the user who created the topic. + * @apiSuccess {String} Topic.updatedById ID of the user who last updated the topic. * * @apiError (Error 400) BadRequest Missing required fields. */ From b8f998d9c7437a0da44d80f0fbceb6d0263c6f1a Mon Sep 17 00:00:00 2001 From: samrth07 Date: Sat, 26 Jul 2025 20:26:40 +0530 Subject: [PATCH 2/7] Increse the size --- src/app.ts | 2 +- src/controllers/project.controller.ts | 5 ----- src/routes/index.ts | 1 - src/routes/projects.ts | 8 +++----- src/routes/topics.ts | 2 +- 5 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/app.ts b/src/app.ts index f1c60e4..ed92227 100644 --- a/src/app.ts +++ b/src/app.ts @@ -32,7 +32,7 @@ app.use(urlencoded({ extended: true })); // 3) Handle file uploads (in-memory) const upload = multer({ storage: multer.memoryStorage(), - limits: { fileSize: 2 * 1024 * 1024 } + limits: { fileSize: 5 * 1024 * 1024 } }); // 4) Mount your routes, injecting `upload` middleware where needed diff --git a/src/controllers/project.controller.ts b/src/controllers/project.controller.ts index fa0242c..66388a2 100644 --- a/src/controllers/project.controller.ts +++ b/src/controllers/project.controller.ts @@ -16,20 +16,16 @@ export const getProjects = async (req: Request, res: Response) => { export const getProjectById = async (req: Request, res: Response) => { - const projectId = parseInt(req.params.projectId); - if (isNaN(projectId)) throw new ApiError("Invalid project ID", 400); const project = await projectService.getProjectById(projectId); res.status(200).json(project); - }; export const createProject = async (req: Request, res: Response) => { - const file = req.file; if (!file) throw new ApiError('Image file not found', 400); @@ -54,7 +50,6 @@ export const createProject = async (req: Request, res: Response) => { export const updateProjects = async (req: Request, res: Response) => { - const projectInfo = req.body.projectData; const projectId = parseInt(req.params.projectId); const updatedById = projectInfo.updatedById; diff --git a/src/routes/index.ts b/src/routes/index.ts index 1d4cc2b..1ccf299 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -11,7 +11,6 @@ import membersRouter from './members' export default function routes(upload: Multer, supabase: SupabaseClient) { const router = Router(); - router.use('/members', membersRouter(upload, supabase)) router.use('/projects', projectsRouter(upload, supabase)) diff --git a/src/routes/projects.ts b/src/routes/projects.ts index b91adff..663d4d8 100644 --- a/src/routes/projects.ts +++ b/src/routes/projects.ts @@ -12,15 +12,13 @@ import { updateProjects } from '../controllers/project.controller' - -function parseCreateProjectData(req : Request, res : Response , next : NextFunction) { +function parseProjectData(req : Request, res : Response , next : NextFunction) { if(req.body.projectData){ try{ const parse = JSON.parse(req.body.projectData); req.body.projectData = parse; }catch(e){ - console.log(e); return res.status(400).json({ message: 'Invalid JSON in projectData field' }); } } @@ -100,7 +98,7 @@ export default function projectsRouter( * @apiError (Error 500) InternalServerError Database error or internal issue */ - router.post('/', upload.single('image') , parseCreateProjectData , createProject ) + router.post('/' , upload.single('image') , parseProjectData , createProject ) // Update Project /** @@ -121,7 +119,7 @@ export default function projectsRouter( * @apiError (Error 500) InternalServerError Database error or unexpected issue */ - router.patch('/:projectId', upload.single('image') , parseCreateProjectData , updateProjects ) + router.patch('/:projectId', upload.single('image') , parseProjectData , updateProjects ) // delete projects diff --git a/src/routes/topics.ts b/src/routes/topics.ts index 55bfcb6..f22c26c 100644 --- a/src/routes/topics.ts +++ b/src/routes/topics.ts @@ -47,7 +47,7 @@ export default function topicRouter() { * @apiSuccess {number} Topic.createdAt Timestamp when the topic was created. * @apiSuccess {number} Topic.updatedAt Timestamp when the topic was last updated. * @apiSuccess {String} Topic.createdById ID of the user who created the topic. - * @apiSuccess {String} Topic.updatedById ID of the user who last updated the topic. + * @apiSuccess {String} Topic-.updatedById ID of the user who last updated the topic. * * @apiError (Error 400) BadRequest Missing required fields. */ From 12835c491d75ca8fac31ec78868950ea8128e5d0 Mon Sep 17 00:00:00 2001 From: samrth07 Date: Sun, 27 Jul 2025 10:57:16 +0530 Subject: [PATCH 3/7] Add delete and upadate functionality of storage image --- src/controllers/project.controller.ts | 17 +- src/routes/projects.ts | 318 +++++++++++++------------- 2 files changed, 173 insertions(+), 162 deletions(-) diff --git a/src/controllers/project.controller.ts b/src/controllers/project.controller.ts index 66388a2..1821604 100644 --- a/src/controllers/project.controller.ts +++ b/src/controllers/project.controller.ts @@ -1,7 +1,7 @@ import * as projectService from "../services/project.service"; import { Request, Response } from "express"; import { ApiError } from "../utils/apiError"; -import { uploadImage } from "../utils/imageUtils"; +import { deleteImage, uploadImage } from "../utils/imageUtils"; import { supabase } from "../app"; @@ -56,9 +56,13 @@ export const updateProjects = async (req: Request, res: Response) => { let imageUrl = null; const file = req.file; + if( !projectId ) throw new ApiError("ProjectId is missng !!!" , 401); if ( file ) { - imageUrl = await uploadImage(supabase, file, 'projects'); + const response = await projectService.getProjectById(projectId); + const fileUlr = response?.imageUrl; + if( !fileUlr ) throw new ApiError("File is not exits"); + imageUrl = await uploadImage(supabase, file, 'projects' , fileUlr); } if (imageUrl) { @@ -66,7 +70,7 @@ export const updateProjects = async (req: Request, res: Response) => { } - if (!projectId || projectInfo.length === 0 || !updatedById) throw new ApiError(" Something is Mising ", 400); + if ( projectInfo.length === 0 || !updatedById) throw new ApiError(" Something is Mising ", 400); const project = await projectService.updateProjects(projectInfo, projectId); res.status(200).json(project) @@ -81,6 +85,13 @@ export const deleteProjects = async (req: Request, res: Response) => { const projectId = parseInt(req.params.projectId); if (!projectId) throw new ApiError(" Send The project id ", 400); + const response = await projectService.getProjectById(projectId); + const fileUrl = response?.imageUrl; + + if(fileUrl){ + await deleteImage(supabase , fileUrl); + } + const deleted = await projectService.deleteProjects(projectId); res.status(200).json(deleted) diff --git a/src/routes/projects.ts b/src/routes/projects.ts index 663d4d8..8463e62 100644 --- a/src/routes/projects.ts +++ b/src/routes/projects.ts @@ -1,28 +1,28 @@ import { NextFunction, Request, Response, Router } from 'express' -import { Multer } from 'multer' +import { Multer } from 'multer' import { SupabaseClient } from '@supabase/supabase-js' import { - addMembers, - createProject, - deleteProjects, - getMembersByProjectId, - getProjectById, - getProjects, - removeMembers, - updateProjects + addMembers, + createProject, + deleteProjects, + getMembersByProjectId, + getProjectById, + getProjects, + removeMembers, + updateProjects } from '../controllers/project.controller' -function parseProjectData(req : Request, res : Response , next : NextFunction) { - - if(req.body.projectData){ - try{ - const parse = JSON.parse(req.body.projectData); - req.body.projectData = parse; - }catch(e){ - return res.status(400).json({ message: 'Invalid JSON in projectData field' }); - } - } - next(); +function parseProjectData(req: Request, res: Response, next: NextFunction) { + + if (req.body.projectData) { + try { + const parse = JSON.parse(req.body.projectData); + req.body.projectData = parse; + } catch (e) { + return res.status(400).json({ message: 'Invalid JSON in projectData field' }); + } + } + next(); } export default function projectsRouter( @@ -31,114 +31,114 @@ export default function projectsRouter( ) { const router = Router(); - // Get all User -/** - * @api {get} /projects/ Get all projects - * @apiName getProjects - * @apiGroup Project - * - * @apiSuccess {Object[]} projects List of all projects - * - * @apiSuccessExample {json} Success-Response: - * HTTP/1.1 200 OK - * [ - * { - * "id": 1, - * "name": "Project Alpha", - * "imageUrl": "https://example.com/image.png", - * "githubUrl": "https://github.com/org/project-alpha", - * "deployUrl": "https://project-alpha.example.com", - * "AdminId": "uuid-string", - * "createdAt": "2025-07-18T10:00:00Z", - * "updatedAt": "2025-07-18T10:00:00Z" - * }, - * { - * "id": 2, - * "name": "Project Beta", - * ... - * } - * ] - * - * @apiError (Error 500) InternalServerError Failed to fetch projects from the database - */ - - router.get('/', getProjects) - - // get Project by Id -/** - * @api {get} /projects/:projectId Get specific project by ID - * @apiName getProjectById - * @apiGroup Project - * - * @apiParam (Path) {UUID} projectId ID of the project - * - * @apiSuccess {Object} project The project object with the given ID - * - * @apiError (Error 404) NotFound No project found with the specified ID - * @apiError (Error 500) InternalServerError Database error or internal issue - */ - - router.get('/:projectId', getProjectById) - - // Create project -/** - * @api {post} /projects/ Create a new project - * @apiName createProject - * @apiGroup Project - * - * @apiBody (FormData) {String} name Name of the project - * @apiBody (FormData) {File} image Image file for the project - * @apiBody (FormData) {String} githubUrl GitHub URL of the project - * @apiBody (FormData) {String} deployUrl Deployment link of the project - * @apiBody (FormData) {UUID} AdminId ID of the admin creating the project - * - * @apiSuccess {Object} project The created project object - * - * @apiError (Error 400) BadRequest Some fields are missing - * @apiError (Error 500) InternalServerError Database error or internal issue - */ - - router.post('/' , upload.single('image') , parseProjectData , createProject ) - - // Update Project - /** - * @api {patch} /projects/:projectId Update a project - * @apiName updateProjects - * @apiGroup Project - * - * @apiParam (Path Params) {Number} projectId ID of the project to update - * @apiBody (Body) {String} [name] Name of the project (optional) - * @apiBody (Body) {String} [githubUrl] GitHub URL of the project (optional) - * @apiBody (Body) {String} [deployUrl] Deployment link of the project (optional) - * @apiBody (Body) {UUID} adminId ID of the admin updating the project (required) - * @apiBody (Form Data) {File} [image] Image file (optional) - * - * @apiSuccess {Object} project Updated project data - * - * @apiError (Error 400) BadRequest Some required fields are missing or invalid - * @apiError (Error 500) InternalServerError Database error or unexpected issue - */ - - router.patch('/:projectId', upload.single('image') , parseProjectData , updateProjects ) + // Get all User + /** + * @api {get} /projects/ Get all projects + * @apiName getProjects + * @apiGroup Project + * + * @apiSuccess {Object[]} projects List of all projects + * + * @apiSuccessExample {json} Success-Response: + * HTTP/1.1 200 OK + * [ + * { + * "id": 1, + * "name": "Project Alpha", + * "imageUrl": "https://example.com/image.png", + * "githubUrl": "https://github.com/org/project-alpha", + * "deployUrl": "https://project-alpha.example.com", + * "AdminId": "uuid-string", + * "createdAt": "2025-07-18T10:00:00Z", + * "updatedAt": "2025-07-18T10:00:00Z" + * }, + * { + * "id": 2, + * "name": "Project Beta", + * ... + * } + * ] + * + * @apiError (Error 500) InternalServerError Failed to fetch projects from the database + */ + + router.get('/', getProjects) + + // get Project by Id + /** + * @api {get} /projects/:projectId Get specific project by ID + * @apiName getProjectById + * @apiGroup Project + * + * @apiParam (Path) {UUID} projectId ID of the project + * + * @apiSuccess {Object} project The project object with the given ID + * + * @apiError (Error 404) NotFound No project found with the specified ID + * @apiError (Error 500) InternalServerError Database error or internal issue + */ + + router.get('/:projectId', getProjectById) + + // Create project + /** + * @api {post} /projects/ Create a new project + * @apiName createProject + * @apiGroup Project + * + * @apiBody (FormData) {String} name Name of the project + * @apiBody (FormData) {File} image Image file for the project + * @apiBody (FormData) {String} githubUrl GitHub URL of the project + * @apiBody (FormData) {String} deployUrl Deployment link of the project + * @apiBody (FormData) {UUID} AdminId ID of the admin creating the project + * + * @apiSuccess {Object} project The created project object + * + * @apiError (Error 400) BadRequest Some fields are missing + * @apiError (Error 500) InternalServerError Database error or internal issue + */ + + router.post('/', upload.single('image'), parseProjectData, createProject) + + // Update Project + /** +* @api {patch} /projects/:projectId Update a project +* @apiName updateProjects +* @apiGroup Project +* +* @apiParam (Path Params) {Number} projectId ID of the project to update +* @apiBody (Body) {String} [name] Name of the project (optional) +* @apiBody (Body) {String} [githubUrl] GitHub URL of the project (optional) +* @apiBody (Body) {String} [deployUrl] Deployment link of the project (optional) +* @apiBody (Body) {UUID} adminId ID of the admin updating the project (required) +* @apiBody (Form Data) {File} [image] Image file (optional) +* +* @apiSuccess {Object} project Updated project data +* +* @apiError (Error 400) BadRequest Some required fields are missing or invalid +* @apiError (Error 500) InternalServerError Database error or unexpected issue +*/ + + router.patch('/:projectId', upload.single('image'), parseProjectData, updateProjects) + + // delete projects - // delete projects + /** + * @api {delete} /projects/:projectId Delete a project + * @apiName deleteProjects + * @apiGroup Project + * + * @apiParam (Path Params) {Number} projectId ID of the project to be deleted + * + * @apiSuccess {Object} deletedProject Details of the deleted project + * + * @apiError (Error 400) BadRequest Some required fields are missing or invalid + * @apiError (Error 500) InternalServerError Internal server error + */ - /** - * @api {delete} /projects/:projectId Delete a project - * @apiName deleteProjects - * @apiGroup Project - * - * @apiParam (Path Params) {Number} projectId ID of the project to be deleted - * - * @apiSuccess {Object} deletedProject Details of the deleted project - * - * @apiError (Error 400) BadRequest Some required fields are missing or invalid - * @apiError (Error 500) InternalServerError Internal server error - */ - - router.delete('/:projectId', deleteProjects ) + router.delete('/:projectId', deleteProjects) /** * @api {get} /projects/:projectId/members Get members enrolled in a project @@ -154,42 +154,42 @@ export default function projectsRouter( */ - router.get('/:projectId/members', getMembersByProjectId ) - - /** - * @api {post} /projects/:projectId/members Add members to a project - * @apiName addMembers - * @apiGroup MemberProject - * - * @apiParam (Path Params) {Number} projectId ID of the project - * @apiBody (Request Body) {UUID[]} memberIds Array of member IDs to add to the project - * - * @apiSuccess {Number} count Number of members successfully added - * - * @apiError (Error 400) BadRequest Some required fields are missing - * @apiError (Error 500) InternalServerError Internal server error - */ - - - router.post('/:projectId/members' , addMembers ) - - // Remover the memnber - /** - * @api {delete} /projects/:projectId/members/:memberId Remove a member from a project - * @apiName removeMember - * @apiGroup MemberProject - * - * @apiParam (Path Params) {Number} projectId ID of the project - * @apiParam (Path Params) {UUID} memberId ID of the member to be removed - * - * @apiSuccess {Object} member The member that was removed - * - * @apiError (Error 400) BadRequest Some required fields are missing - * @apiError (Error 500) InternalServerError Internal server error - */ + router.get('/:projectId/members', getMembersByProjectId) - - router.delete( '/:projectId/members/:memberId', removeMembers) + /** +* @api {post} /projects/:projectId/members Add members to a project +* @apiName addMembers +* @apiGroup MemberProject +* +* @apiParam (Path Params) {Number} projectId ID of the project +* @apiBody (Request Body) {UUID[]} memberIds Array of member IDs to add to the project +* +* @apiSuccess {Number} count Number of members successfully added +* +* @apiError (Error 400) BadRequest Some required fields are missing +* @apiError (Error 500) InternalServerError Internal server error +*/ + + + router.post('/:projectId/members', addMembers) + + // Remover the memnber + /** +* @api {delete} /projects/:projectId/members/:memberId Remove a member from a project +* @apiName removeMember +* @apiGroup MemberProject +* +* @apiParam (Path Params) {Number} projectId ID of the project +* @apiParam (Path Params) {UUID} memberId ID of the member to be removed +* +* @apiSuccess {Object} member The member that was removed +* +* @apiError (Error 400) BadRequest Some required fields are missing +* @apiError (Error 500) InternalServerError Internal server error +*/ + + + router.delete('/:projectId/members/:memberId', removeMembers) return router; From 5c0925c6e0d1ed0222cb3005dffdd2217d662648 Mon Sep 17 00:00:00 2001 From: samrth07 Date: Sun, 27 Jul 2025 11:08:43 +0530 Subject: [PATCH 4/7] Test are fix --- tests/Project.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Project.test.ts b/tests/Project.test.ts index 7fa435c..6678b06 100644 --- a/tests/Project.test.ts +++ b/tests/Project.test.ts @@ -23,8 +23,10 @@ jest.mock('../src/app', () => ({ // Mock image upload utility jest.mock('../src/utils/imageUtils', () => ({ uploadImage: jest.fn().mockResolvedValue('https://fake-url.com/projects/image.png'), + deleteImage: jest.fn().mockResolvedValue('https://fake-url.com/projects/image.png'), })); + // Reusable mock response object const mockRes = () => { const res = {} as Response; From 216a7033ed53a53443386d8f68ed811db0bff835 Mon Sep 17 00:00:00 2001 From: Sherin Thomas Date: Sun, 27 Jul 2025 14:47:18 +0530 Subject: [PATCH 5/7] Minor Changes in Update and Delete Achievement controllers --- src/controllers/achievement.controller.ts | 44 ++++++++++++++--------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/controllers/achievement.controller.ts b/src/controllers/achievement.controller.ts index f3384ec..cf822f8 100644 --- a/src/controllers/achievement.controller.ts +++ b/src/controllers/achievement.controller.ts @@ -1,6 +1,6 @@ import { Request, Response } from "express"; import * as achievementService from "../services/achievement.service"; -import { uploadImage } from "../utils/imageUtils"; +import { uploadImage, deleteImage } from "../utils/imageUtils"; import { supabase } from "../app"; import { ApiError } from "../utils/apiError"; @@ -80,10 +80,6 @@ export const updateAchievementById = async (req: Request, res: Response) => { const file = req.file; let imageUrl: string | undefined; - if (file) { - imageUrl = await uploadImage(supabase, file, 'achievements'); - } - let achievementData = req.body.achievementData; if (typeof achievementData === 'string') { try { @@ -99,25 +95,30 @@ export const updateAchievementById = async (req: Request, res: Response) => { throw new ApiError("updatedById is required", 400); } - if ( - !title && - !description && - !achievedAt && - !imageUrl && - (!Array.isArray(memberIds) || memberIds.length === 0) - ) { - throw new ApiError("At least one field must be provided for update", 400); - } - + const existingAchievement = await achievementService.getAchievementById(achievementId); if (!existingAchievement) { throw new ApiError("Achievement not found", 404); } - + + if (file) { + imageUrl = await uploadImage(supabase, file, 'achievements', existingAchievement.imageUrl ); + } + if (imageUrl) { achievementData.imageUrl = imageUrl; } - + + if ( + !title && + !description && + !achievedAt && + !imageUrl && + (!Array.isArray(memberIds) || memberIds.length === 0) + ) { + throw new ApiError("At least one field must be provided for update", 400); + } + const updatedAchievement = await achievementService.updateAchievementById( achievementId, achievementData @@ -141,6 +142,15 @@ export const deleteAchievementById = async (req: Request, res: Response) => { throw new ApiError("Invalid achievement ID", 400); } + const existingAchievement = await achievementService.getAchievementById(achievementId); + if (!existingAchievement) { + throw new ApiError("Achievement not found", 404); + } + + if (existingAchievement.imageUrl) { + await deleteImage(supabase, existingAchievement.imageUrl); + } + await achievementService.deleteAchievementById(achievementId); res.status(200).json({ From d2b016ff5fd8177fb111d6803666c9a2f546792b Mon Sep 17 00:00:00 2001 From: Sherin Thomas Date: Sun, 27 Jul 2025 15:00:32 +0530 Subject: [PATCH 6/7] Some fixes in Delte Acheivement test --- src/app.ts | 2 +- tests/Achievement.test.ts | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/app.ts b/src/app.ts index ed92227..f1c60e4 100644 --- a/src/app.ts +++ b/src/app.ts @@ -32,7 +32,7 @@ app.use(urlencoded({ extended: true })); // 3) Handle file uploads (in-memory) const upload = multer({ storage: multer.memoryStorage(), - limits: { fileSize: 5 * 1024 * 1024 } + limits: { fileSize: 2 * 1024 * 1024 } }); // 4) Mount your routes, injecting `upload` middleware where needed diff --git a/tests/Achievement.test.ts b/tests/Achievement.test.ts index 169defc..ddafbbb 100644 --- a/tests/Achievement.test.ts +++ b/tests/Achievement.test.ts @@ -1,6 +1,6 @@ import { createAchievement, getAchievements, getAchievementById, updateAchievementById, deleteAchievementById, removeMemberFromAchievement } from '../src/controllers/achievement.controller'; import * as achievementService from '../src/services/achievement.service'; -import { uploadImage } from '../src/utils/imageUtils'; +import { uploadImage, deleteImage } from '../src/utils/imageUtils'; import { ApiError } from '../src/utils/apiError'; jest.mock('../src/app', () => ({ @@ -24,8 +24,10 @@ jest.mock('../src/routes/achievements', () => { jest.mock('../src/utils/imageUtils', () => ({ uploadImage: jest.fn(), + deleteImage: jest.fn(), })); + const mockedUploadImage = uploadImage as jest.Mock; describe('createAchievement (with image upload)', () => { @@ -368,6 +370,7 @@ describe('updateAchievementById', () => { }); }); +const mockedDeleteImage = deleteImage as jest.Mock; describe('deleteAchievementById', () => { it('should delete the achievement and return 200 success message', async () => { @@ -392,14 +395,26 @@ describe('deleteAchievementById', () => { createdAt: new Date(), updatedById: null, updatedAt: new Date(), + + createdBy: { id: 'admin_123', name: 'Admin' }, + updatedBy: null, + members: [], }; + jest + .spyOn(achievementService, 'getAchievementById') + .mockResolvedValue(mockDeletedAchievement); + jest .spyOn(achievementService, 'deleteAchievementById') .mockResolvedValue(mockDeletedAchievement); + mockedDeleteImage.mockResolvedValue(undefined); + await deleteAchievementById(req, res); + expect(achievementService.getAchievementById).toHaveBeenCalledWith(1); + expect(mockedDeleteImage).toHaveBeenCalledWith(expect.anything(), mockDeletedAchievement.imageUrl); expect(achievementService.deleteAchievementById).toHaveBeenCalledWith(1); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith({ From df481bddc2d80722c8be997d3907ca53a5139ea4 Mon Sep 17 00:00:00 2001 From: Sherin Thomas Date: Sun, 27 Jul 2025 15:21:41 +0530 Subject: [PATCH 7/7] Fixed topic routes api annotations --- src/routes/topics.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/topics.ts b/src/routes/topics.ts index f22c26c..55bfcb6 100644 --- a/src/routes/topics.ts +++ b/src/routes/topics.ts @@ -47,7 +47,7 @@ export default function topicRouter() { * @apiSuccess {number} Topic.createdAt Timestamp when the topic was created. * @apiSuccess {number} Topic.updatedAt Timestamp when the topic was last updated. * @apiSuccess {String} Topic.createdById ID of the user who created the topic. - * @apiSuccess {String} Topic-.updatedById ID of the user who last updated the topic. + * @apiSuccess {String} Topic.updatedById ID of the user who last updated the topic. * * @apiError (Error 400) BadRequest Missing required fields. */