diff --git a/src/controllers/member.controller.ts b/src/controllers/member.controller.ts index 642088e..267622f 100644 --- a/src/controllers/member.controller.ts +++ b/src/controllers/member.controller.ts @@ -82,7 +82,7 @@ export const updateAMember = const oldData = await memberService.getDetails(memberId); const oldImage = oldData?.profilePhoto; - if(oldImage) await deleteImage(supabase, oldImage); + if(oldImage) await uploadImage(supabase, req.file, "members", oldImage); const imageUrl = await uploadImage(supabase, req.file, "members"); body.profilePhoto = imageUrl; @@ -90,9 +90,10 @@ export const updateAMember = await memberService.updateMember(memberId, body); + const updatedData = await memberService.getDetails(memberId); res .status(200) - .json({ success: true, message: "Updated member details successfully" }); + .json({ success: true, user: updatedData }); }; // Get all unapproved members diff --git a/src/routes/members.ts b/src/routes/members.ts index e1653fb..0d0042e 100644 --- a/src/routes/members.ts +++ b/src/routes/members.ts @@ -10,6 +10,15 @@ export default function membersRouter( ) { const router = express.Router(); + /** + * @api {get} /members/unapproved Get unapproved members + * @apiName GetUnapprovedMembers + * @apiGroup Member + * + * @apiSuccess {Object[]} unapprovedMembers List of unapproved members. + */ + router.get("/unapproved", memberCtrl.getUnapprovedMembers); + /** * @api {get} /members/:memberId Get a member's details * @apiName GetUserDetails @@ -89,15 +98,6 @@ export default function membersRouter( memberCtrl.updateAMember(supabase), ); - /** - * @api {get} /members/unapproved Get unapproved members - * @apiName GetUnapprovedMembers - * @apiGroup Member - * - * @apiSuccess {Object[]} unapprovedMembers List of unapproved members. - */ - router.get("/unapproved", memberCtrl.getUnapprovedMembers); - /** * @api {patch} /members/approve/:memberId Approve/reject a member * @apiName UpdateApprovalRequest @@ -113,7 +113,7 @@ export default function membersRouter( router.patch("/approve/:memberId", memberCtrl.updateRequest); /** - * @api {get} /members/achievements/:memberId Get member's achievements + * @api {get} /members/:memberId/achievements Get member's achievements * @apiName GetUserAchievements * @apiGroup Member * @@ -121,10 +121,10 @@ export default function membersRouter( * * @apiSuccess {Object[]} achievements List of achievements. */ - router.get("/achievements/:memberId", memberCtrl.getUserAchievements); + router.get("/:memberId/achievements", memberCtrl.getUserAchievements); /** - * @api {get} /api/members/projects/:memberId Get member's projects + * @api {get} /api/members/:memberId/projects Get member's projects * @apiName GetUserProjects * @apiGroup Member * @@ -132,10 +132,10 @@ export default function membersRouter( * * @apiSuccess {Object[]} projects List of projects. */ - router.get("/projects/:memberId", memberCtrl.getUserProjects); + router.get("/:memberId/projects", memberCtrl.getUserProjects); /** - * @api {get} /members/interviews/:memberId Get member's interviews + * @api {get} /members/:memberId/interviews Get member's interviews * @apiName GetUserInterviews * @apiGroup Member * @@ -143,7 +143,7 @@ export default function membersRouter( * * @apiSuccess {Object[]} interviews List of interviews. */ - router.get("/interviews/:memberId", memberCtrl.getUserInterviews); + router.get("/:memberId/interviews", memberCtrl.getUserInterviews); return router; } \ No newline at end of file diff --git a/tests/Member.test.ts b/tests/Member.test.ts index 8a531e1..26860df 100644 --- a/tests/Member.test.ts +++ b/tests/Member.test.ts @@ -3,7 +3,7 @@ import { createAMember, updateAMember } from '../src/controllers/member.controll import * as memberService from '../src/services/member.service'; import { ApiError } from '../src/utils/apiError'; import { SupabaseClient } from '@supabase/supabase-js'; -import { uploadImage } from '../src/utils/imageUtils'; +import { uploadImage, deleteImage } from '../src/utils/imageUtils'; jest.mock('../src/db/client', () => ({ prisma: { @@ -68,7 +68,7 @@ describe('Member Controller - updateAMember', () => { jest.clearAllMocks(); }); - it('should update member and respond with 200', async () => { + it('should update member and return updated data (no image)', async () => { const req = { params: { memberId: 'abc-123' }, body: { github: 'https://github.com/shrutii' }, @@ -77,14 +77,14 @@ describe('Member Controller - updateAMember', () => { const res = mockResponse(); - const mockMember = { + const updatedMember = { id: '123', name: 'Test User', email: 'test@example.com', phone: null, bio: null, profilePhoto: null, - github: 'testgithub', + github: 'https://github.com/shrutii', linkedin: null, twitter: null, leetcode: null, @@ -100,38 +100,38 @@ describe('Member Controller - updateAMember', () => { updatedAt: new Date(), }; - const spy = jest.spyOn(memberService, 'updateMember').mockResolvedValue(mockMember); + const spyUpdate = jest.spyOn(memberService, 'updateMember').mockResolvedValue(updatedMember); + const spyGet = jest.spyOn(memberService, 'getDetails').mockResolvedValue(updatedMember); const handler = updateAMember(mockSupabase); await handler(req, res); - expect(spy).toHaveBeenCalledWith('abc-123', req.body); + expect(spyUpdate).toHaveBeenCalledWith('abc-123', req.body); + expect(spyGet).toHaveBeenCalledTimes(1); expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith({ success: true, - message: 'Updated member details successfully', + user: updatedMember, }); }); - it('should upload image and update profilePhoto', async () => { + it('should upload new image, handle old image, update member, and return updated data', async () => { const req = { params: { memberId: 'abc-123' }, body: {}, - file: { buffer: Buffer.from('data') }, + file: { buffer: Buffer.from('fake-image-data') }, } as unknown as Request; const res = mockResponse(); - (uploadImage as jest.Mock).mockResolvedValue('http://image.url'); - - const mockMember = { + const oldMember = { id: '123', - name: 'Test User', - email: 'test@example.com', + name: 'Old User', + email: 'old@example.com', phone: null, bio: null, - profilePhoto: 'http://image.url', - github: 'testgithub', + profilePhoto: 'https://old.url/image.png', + github: null, linkedin: null, twitter: null, leetcode: null, @@ -147,17 +147,49 @@ describe('Member Controller - updateAMember', () => { updatedAt: new Date(), }; - const spy = jest.spyOn(memberService, 'updateMember').mockResolvedValue(mockMember); + const updatedMember = { + ...oldMember, + profilePhoto: 'https://new.url/image.png', + }; + + (uploadImage as jest.Mock) + .mockResolvedValueOnce(undefined) + .mockResolvedValueOnce('https://new.url/image.png'); + + jest.spyOn(memberService, 'getDetails') + .mockResolvedValueOnce(oldMember) + .mockResolvedValueOnce(updatedMember); + + const spyUpdate = jest + .spyOn(memberService, 'updateMember') + .mockResolvedValue(updatedMember); const handler = updateAMember(mockSupabase); await handler(req, res); - expect(uploadImage).toHaveBeenCalled(); - expect(spy).toHaveBeenCalledWith('abc-123', { profilePhoto: 'http://image.url' }); + expect(uploadImage).toHaveBeenNthCalledWith( + 1, + mockSupabase, + req.file, + 'members', + 'https://old.url/image.png' + ); + + expect(uploadImage).toHaveBeenNthCalledWith( + 2, + mockSupabase, + req.file, + 'members' + ); + + expect(spyUpdate).toHaveBeenCalledWith('abc-123', { + profilePhoto: 'https://new.url/image.png', + }); + expect(res.status).toHaveBeenCalledWith(200); expect(res.json).toHaveBeenCalledWith({ success: true, - message: 'Updated member details successfully', + user: updatedMember, }); }); -}); +}); \ No newline at end of file