Skip to content

Commit d9f9fbb

Browse files
Merge pull request #8 from call-0f-code/project-routes
Project routes
2 parents d180288 + 6b8d5d4 commit d9f9fbb

12 files changed

Lines changed: 1091 additions & 217 deletions

File tree

bun.lock

Lines changed: 216 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
"devDependencies": {
3333
"@eslint/js": "^9.31.0",
3434
"@types/bun": "latest",
35+
"@types/jest": "^30.0.0",
3536
"@typescript-eslint/eslint-plugin": "^8.36.0",
3637
"@typescript-eslint/parser": "^8.36.0",
3738
"eslint": "^9.31.0",
@@ -51,7 +52,6 @@
5152
"@supabase/supabase-js": "^2.50.5",
5253
"@types/cors": "^2.8.19",
5354
"@types/express": "^5.0.3",
54-
"@types/jest": "^30.0.0",
5555
"@types/multer": "^2.0.0",
5656
"@types/node": "^24.0.13",
5757
"@types/uuid": "^10.0.0",
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- Check for nulls before altering
2+
DO $$
3+
BEGIN
4+
IF EXISTS (SELECT 1 FROM "Project" WHERE "imageUrl" IS NULL OR "githubUrl" IS NULL) THEN
5+
RAISE EXCEPTION 'Migration aborted: Some rows in "Project" have NULL in "imageUrl" or "githubUrl"';
6+
END IF;
7+
END
8+
$$;
9+
10+
-- AlterTable safely
11+
ALTER TABLE "Project"
12+
ALTER COLUMN "imageUrl" SET NOT NULL,
13+
ALTER COLUMN "githubUrl" SET NOT NULL;

prisma/schema.prisma

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ model MemberAchievement {
102102
model Project {
103103
id Int @id @default(autoincrement())
104104
name String
105-
imageUrl String?
106-
githubUrl String?
105+
imageUrl String
106+
githubUrl String
107107
deployUrl String?
108108
109109
// Audit fields
Lines changed: 118 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,144 @@
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";
5+
import { supabase } from "../app";
6+
47

58
export const getProjects = async (req: Request, res: Response) => {
6-
try {
7-
const projects = await projectService.getPrjects();
8-
res.json(projects);
9-
} catch (error) {
10-
throw new ApiError("No project found !!!", 404);
11-
}
9+
10+
11+
const projects = await projectService.getProjects();
12+
res.status(200).json(projects);
13+
1214
};
1315

16+
1417
export const getProjectById = async (req: Request, res: Response) => {
15-
try {
16-
const projectId = parseInt(req.params.projectId);
17-
const project = await projectService.getProjectById(projectId);
18-
res.json(project);
19-
} catch (error) {
20-
throw new ApiError("No project with this ID", 404);
21-
}
18+
19+
20+
const projectId = parseInt(req.params.projectId);
21+
22+
if (isNaN(projectId)) throw new ApiError("Invalid project ID", 400);
23+
24+
const project = await projectService.getProjectById(projectId);
25+
res.status(200).json(project);
26+
27+
2228
};
2329

2430
export const createProject = async (req: Request, res: Response) => {
25-
try {
26-
const projectContent = {
27-
name: req.body.name,
28-
imageUrl: req.body.imageUrl,
29-
githubUrl: req.body.githubUrl,
30-
deployUrl: req.body.deployUrl,
31-
adminId: req.AdminId,
32-
};
33-
34-
const project = await projectService.createProject(projectContent);
35-
res.json(project);
36-
} catch (error) {
37-
throw new ApiError(error as string, 404);
38-
}
31+
32+
33+
const file = req.file;
34+
if (!file) throw new ApiError('Image file not found', 400);
35+
36+
const imageUrl = await uploadImage(supabase, file, 'projects');
37+
38+
if (!imageUrl) throw new ApiError("Image url is missing", 400);
39+
40+
if (!req.body.projectData.name || !req.body.projectData.githubUrl) throw new ApiError(" fiels is missing ", 400);
41+
42+
const projectContent = {
43+
name: req.body.projectData.name,
44+
imageUrl: imageUrl,
45+
githubUrl: req.body.projectData.githubUrl,
46+
deployUrl: req.body.deployUrl,
47+
AdminId: req.body.projectData.adminId,
48+
};
49+
50+
const project = await projectService.createProject(projectContent);
51+
res.status(200).json(project);
52+
3953
};
4054

4155
export const updateProjects = async (req: Request, res: Response) => {
42-
try {
43-
const projectInfo = req.body;
44-
const projectId = parseInt(req.params.projectId);
45-
if (!projectId) throw new ApiError(" Send The project id ", 401);
46-
47-
const project = await projectService.updateProjects(projectInfo, projectId);
48-
res.json(project);
49-
} catch (error) {
50-
throw new ApiError(error as string, 404);
56+
57+
58+
const projectInfo = req.body.projectData;
59+
const projectId = parseInt(req.params.projectId);
60+
const updatedById = projectInfo.updatedById;
61+
62+
let imageUrl = null;
63+
const file = req.file;
64+
65+
if (file) {
66+
imageUrl = await uploadImage(supabase, file, 'projects');
5167
}
52-
};
5368

54-
export const deleteProjects = async (req: Request, res: Response) => {
55-
try {
56-
const projectId = parseInt(req.params.projectId);
57-
if (!projectId) throw new ApiError(" Send The project id ", 401);
58-
59-
const deleted = await projectService.deleteProjects(projectId);
60-
res.json(deleted);
61-
} catch (error) {
62-
console.log(error);
63-
throw new ApiError(error as string, 404);
69+
if (imageUrl) {
70+
projectInfo.imageUrl = imageUrl;
6471
}
65-
};
72+
73+
74+
if (!projectId || projectInfo.length === 0 || !updatedById) throw new ApiError(" Something is Mising ", 400);
75+
76+
const project = await projectService.updateProjects(projectInfo, projectId);
77+
res.status(200).json(project)
78+
79+
80+
}
81+
82+
83+
export const deleteProjects = async (req: Request, res: Response) => {
84+
85+
86+
const projectId = parseInt(req.params.projectId);
87+
if (!projectId) throw new ApiError(" Send The project id ", 400);
88+
89+
const deleted = await projectService.deleteProjects(projectId);
90+
res.status(200).json(deleted)
91+
92+
93+
94+
}
6695

6796
export const getMembersByProjectId = async (req: Request, res: Response) => {
68-
try {
69-
const projectId = parseInt(req.params.ProjectId);
7097

71-
if (!projectId) throw new ApiError(" Project Id required !!! ", 401);
7298

73-
const members = await projectService.getMembersByProjectId(projectId);
74-
res.json(members);
75-
} catch (error) {
76-
throw new ApiError(error as string, 404);
77-
}
78-
};
99+
const projectId = parseInt(req.params.projectId);
100+
if (!projectId) throw new ApiError(" Project Id required !!! ", 400);
101+
102+
const members = await projectService.getMembersByProjectId(projectId);
103+
res.status(200).json(members)
104+
105+
106+
107+
108+
}
79109

80110
export const addMembers = async (req: Request, res: Response) => {
81-
try {
82-
const data = {
83-
projectId: parseInt(req.params.projectId),
84-
memberId: req.body.memberId,
85-
};
86-
87-
const member = await projectService.addMembers(data);
88-
res.json(member);
89-
} catch (error) {
90-
console.log(error);
91-
throw new ApiError(error as string, 404);
92-
}
93-
};
111+
112+
113+
const projectId = parseInt(req.params.projectId);
114+
const memberData = req.body.memberId;
115+
if (!projectId || !memberData || memberData.length === 0) throw new ApiError(" field is missing ", 400);
116+
117+
const data = memberData.map((memberId: string) => ({
118+
projectId,
119+
memberId
120+
}))
121+
122+
const member = await projectService.addMembers(data);
123+
res.status(200).json(member);
124+
125+
126+
}
127+
94128

95129
export const removeMembers = async (req: Request, res: Response) => {
96-
try {
97-
const data = {
98-
projectId: parseInt(req.params.projectId),
99-
memberId: req.body.memberId,
100-
};
101-
102-
const removedMember = await projectService.removeMembers(data);
103-
res.json(removedMember);
104-
} catch (error) {
105-
throw new ApiError(error as string, 404);
130+
131+
132+
const data = {
133+
projectId: parseInt(req.params.projectId),
134+
memberId: req.params.memberId
106135
}
107-
};
136+
137+
if (!data.projectId || !data.memberId) throw new ApiError(' Field is missing !!!', 400);
138+
139+
const removedMember = await projectService.removeMembers(data);
140+
res.status(200).json(removedMember);
141+
142+
143+
}
144+

src/controllers/question.controller.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const getQuestionByTopicId = async (req: Request, res: Response) => {
1616
});
1717
};
1818

19+
1920
export const addQuestion = async (req: Request, res: Response) => {
2021
const topicId = parseInt(req.params.topicId);
2122
const { questionName, difficulty, link } = req.body;

src/routes/index.ts

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,12 @@ export default function routes(upload: Multer, supabase: SupabaseClient) {
1818

1919
router.use('/interviews', interviewRouter(upload, supabase));
2020

21-
2221
router.use('/topics',topicRouter());
2322

24-
router.use("/projects", projectsRouter(upload, supabase));
25-
26-
router.use("/topics", topicRouter());
27-
2823
router.use("/questions", quetionsRouter());
2924

3025
router.use("/progress", progressRouter());
3126

3227
return router;
3328
}
3429

35-
/*
36-
write your routes like this, skip the paramaeters in the exported function if your routes don't need supabase and multer
37-
38-
import { Router } from 'express'
39-
import { Multer } from 'multer'
40-
import * as memberCtrl from '../controllers/member.controller'
41-
import { SupabaseClient } from '@supabase/supabase-js'
42-
43-
export default function membersRouter(
44-
upload: Multer,
45-
supabase: SupabaseClient
46-
) {
47-
const router = Router()
48-
49-
// Photo upload endpoint:
50-
router.post(
51-
'/:memberId/photo',
52-
upload.single('photo'),
53-
(req, res, next) => memberCtrl.uploadPhoto(req, res, next, supabase)
54-
)
55-
56-
return router
57-
}
58-
59-
*/

0 commit comments

Comments
 (0)