Skip to content

Commit d684b3c

Browse files
committed
2 parents a5cb2ca + 43bf031 commit d684b3c

15 files changed

Lines changed: 429 additions & 487 deletions

File tree

bun.lock

Lines changed: 27 additions & 209 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
-- AlterTable
2+
ALTER TABLE "Member" ALTER COLUMN "passoutYear" DROP NOT NULL;

prisma/schema.prisma

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ model Member {
2626
leetcode String?
2727
codechef String?
2828
codeforces String?
29-
passoutYear DateTime
29+
passoutYear DateTime?
3030
isApproved Boolean @default(false)
3131
isManager Boolean @default(false)
3232
createdAt DateTime @default(now())

src/controllers/achievement.controller.ts

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Request, Response } from "express";
22
import * as achievementService from "../services/achievement.service";
3-
import { uploadImage } from "../utils/imageUtils";
3+
import { uploadImage, deleteImage } from "../utils/imageUtils";
44
import { supabase } from "../app";
55
import { ApiError } from "../utils/apiError";
66

@@ -73,19 +73,16 @@ export const createAchievement = async (req: Request, res: Response) => {
7373

7474
export const updateAchievementById = async (req: Request, res: Response) => {
7575
const achievementId = parseInt(req.params.achievementId);
76+
7677
if (!achievementId || isNaN(achievementId)) {
7778
throw new ApiError("Invalid achievement ID", 400);
7879
}
7980

8081
const file = req.file;
8182
let imageUrl: string | undefined;
8283

83-
if (file) {
84-
imageUrl = await uploadImage(supabase, file, 'achievements');
85-
}
86-
8784
let achievementData = req.body.achievementData;
88-
if (typeof achievementData === 'string') {
85+
if (typeof achievementData === "string") {
8986
try {
9087
achievementData = JSON.parse(achievementData);
9188
} catch (e) {
@@ -99,28 +96,31 @@ export const updateAchievementById = async (req: Request, res: Response) => {
9996
throw new ApiError("updatedById is required", 400);
10097
}
10198

102-
if (
103-
!title &&
104-
!description &&
105-
!achievedAt &&
106-
!imageUrl &&
107-
(!Array.isArray(memberIds) || memberIds.length === 0)
108-
) {
109-
throw new ApiError("At least one field must be provided for update", 400);
110-
}
111-
11299
const existingAchievement = await achievementService.getAchievementById(achievementId);
113100
if (!existingAchievement) {
114101
throw new ApiError("Achievement not found", 404);
115102
}
116103

104+
if (file) {
105+
imageUrl = await uploadImage(supabase, file, "achievements", existingAchievement.imageUrl);
106+
}
107+
108+
const { memberIds: _, ...updatePayload } = achievementData;
109+
117110
if (imageUrl) {
118-
achievementData.imageUrl = imageUrl;
111+
updatePayload.imageUrl = imageUrl;
112+
}
113+
114+
const hasSomethingToUpdate =
115+
title || description || achievedAt || imageUrl || (Array.isArray(memberIds) && memberIds.length > 0);
116+
117+
if (!hasSomethingToUpdate) {
118+
throw new ApiError("At least one field (title, description, achievedAt, image, or memberIds) must be provided for update", 400);
119119
}
120120

121121
const updatedAchievement = await achievementService.updateAchievementById(
122122
achievementId,
123-
achievementData
123+
updatePayload
124124
);
125125

126126
if (Array.isArray(memberIds) && memberIds.length > 0) {
@@ -141,6 +141,15 @@ export const deleteAchievementById = async (req: Request, res: Response) => {
141141
throw new ApiError("Invalid achievement ID", 400);
142142
}
143143

144+
const existingAchievement = await achievementService.getAchievementById(achievementId);
145+
if (!existingAchievement) {
146+
throw new ApiError("Achievement not found", 404);
147+
}
148+
149+
if (existingAchievement.imageUrl) {
150+
await deleteImage(supabase, existingAchievement.imageUrl);
151+
}
152+
144153
await achievementService.deleteAchievementById(achievementId);
145154

146155
res.status(200).json({

src/controllers/member.controller.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import { SupabaseClient } from "@supabase/supabase-js";
77
// List all approved members
88
export const listAllApprovedMembers = async (req: Request, res: Response) => {
99

10-
const {email, password} = req.query;
10+
const {email} = req.query;
1111

12-
if(email && password) {
12+
if(email) {
1313

1414
const user = await memberService.getUserByEmail(email as string);
1515

src/controllers/project.controller.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as projectService from "../services/project.service";
22
import { Request, Response } from "express";
33
import { ApiError } from "../utils/apiError";
4-
import { uploadImage } from "../utils/imageUtils";
4+
import { deleteImage, uploadImage } from "../utils/imageUtils";
55
import { supabase } from "../app";
66

77

@@ -16,20 +16,16 @@ export const getProjects = async (req: Request, res: Response) => {
1616

1717
export const getProjectById = async (req: Request, res: Response) => {
1818

19-
2019
const projectId = parseInt(req.params.projectId);
21-
2220
if (isNaN(projectId)) throw new ApiError("Invalid project ID", 400);
2321

2422
const project = await projectService.getProjectById(projectId);
2523
res.status(200).json(project);
2624

27-
2825
};
2926

3027
export const createProject = async (req: Request, res: Response) => {
3128

32-
3329
const file = req.file;
3430
if (!file) throw new ApiError('Image file not found', 400);
3531

@@ -43,7 +39,7 @@ export const createProject = async (req: Request, res: Response) => {
4339
name: req.body.projectData.name,
4440
imageUrl: imageUrl,
4541
githubUrl: req.body.projectData.githubUrl,
46-
deployUrl: req.body.deployUrl,
42+
deployUrl: req.body.projectData.deployUrl,
4743
AdminId: req.body.projectData.adminId,
4844
};
4945

@@ -54,24 +50,27 @@ export const createProject = async (req: Request, res: Response) => {
5450

5551
export const updateProjects = async (req: Request, res: Response) => {
5652

57-
5853
const projectInfo = req.body.projectData;
5954
const projectId = parseInt(req.params.projectId);
6055
const updatedById = projectInfo.updatedById;
6156

6257
let imageUrl = null;
6358
const file = req.file;
59+
if( !projectId ) throw new ApiError("ProjectId is missng !!!" , 401);
6460

65-
if (file) {
66-
imageUrl = await uploadImage(supabase, file, 'projects');
61+
if ( file ) {
62+
const response = await projectService.getProjectById(projectId);
63+
const fileUlr = response?.imageUrl;
64+
if( !fileUlr ) throw new ApiError("File is not exits");
65+
imageUrl = await uploadImage(supabase, file, 'projects' , fileUlr);
6766
}
6867

6968
if (imageUrl) {
7069
projectInfo.imageUrl = imageUrl;
7170
}
7271

7372

74-
if (!projectId || projectInfo.length === 0 || !updatedById) throw new ApiError(" Something is Mising ", 400);
73+
if ( projectInfo.length === 0 || !updatedById) throw new ApiError(" Something is Mising ", 400);
7574

7675
const project = await projectService.updateProjects(projectInfo, projectId);
7776
res.status(200).json(project)
@@ -86,6 +85,13 @@ export const deleteProjects = async (req: Request, res: Response) => {
8685
const projectId = parseInt(req.params.projectId);
8786
if (!projectId) throw new ApiError(" Send The project id ", 400);
8887

88+
const response = await projectService.getProjectById(projectId);
89+
const fileUrl = response?.imageUrl;
90+
91+
if(fileUrl){
92+
await deleteImage(supabase , fileUrl);
93+
}
94+
8995
const deleted = await projectService.deleteProjects(projectId);
9096
res.status(200).json(deleted)
9197

src/routes/achievements.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import express from 'express';
22
import * as acheivementsCtrl from '../controllers/achievement.controller';
3-
import { supabase } from '../app';
43
import { Multer } from 'multer';
54
import { SupabaseClient } from '@supabase/supabase-js';
65

src/routes/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import membersRouter from './members'
1111

1212
export default function routes(upload: Multer, supabase: SupabaseClient) {
1313
const router = Router();
14-
1514
router.use('/members', membersRouter(upload, supabase))
1615

1716
router.use('/projects', projectsRouter(upload, supabase))

src/routes/members.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import express from "express";
22
import * as memberCtrl from "../controllers/member.controller";
33
import { Multer } from "multer";
4-
import { supabase } from "../app";
54
import { SupabaseClient } from "@supabase/supabase-js";
65

76
export default function membersRouter(

src/routes/progress.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,17 @@ export default function progressRouter() {
1515
* @apiParam {String} memberId ID of the member to retrieve completed questions for.
1616
*
1717
* @apiSuccess {String="SUCCESS"} status Response status.
18-
* @apiSuccess {Object[]} completedQuestion List of completed questions.
19-
* @apiSuccess {Number} completedQuestion.questionId Id of the completed question.
18+
* @apiSuccess {Object[]} completedQuestion List of questions inside the topic.
19+
* @apiSuccess {Object} completedQuestion[].question Question object.
20+
* @apiSuccess {Number} completedQuestion[].question.id Question ID.
21+
* @apiSuccess {String} completedQuestion[].question.questionName Name of the question.
22+
* @apiSuccess {String} completedQuestion[].question.link Link to the question.
23+
* @apiSuccess {String="Easy","Medium","Hard"} completedQuestion[].question.difficulty Difficulty level of the question.
24+
* @apiSuccess {Number} completedQuestion[].question.topicId Topic ID associated with the question.
25+
* @apiSuccess {Number} completedQuestion[].question.createdAt Timestamp when the question was created (Unix timestamp).
26+
* @apiSuccess {Number} completedQuestion[].question.updatedAt Timestamp when the question was last updated (Unix timestamp).
27+
* @apiSuccess {String} completedQuestion[].question.createdById ID of the user who created the question.
28+
* @apiSuccess {String} completedQuestion[].question.updatedById ID of the user who last updated the question.
2029
*
2130
* @apiError (Error 400) BadRequest Missing required fields.
2231
* @apiError (Error 500) InternalServerError Error while fetching completed questions.
@@ -38,7 +47,7 @@ export default function progressRouter() {
3847
* @apiError (Error 500) InternalServerError Error while toggling question completion.
3948
*/
4049
router.patch(
41-
"/:memeberId/questions/:questionId/completed/toggle",
50+
"/:memberId/questions/:questionId/completed/toggle",
4251
toggleQuestions,
4352
);
4453

0 commit comments

Comments
 (0)