From 58f40014ebc6c1468451b30ebfbf77cf8c6b12dc Mon Sep 17 00:00:00 2001 From: Mayank Singh Rawat Date: Wed, 3 Jun 2026 13:38:19 +0530 Subject: [PATCH 1/5] fix(opensource): trim search query before database lookup --- .../module/opensource/opensource.routes.ts | 19 ++++++++------- .../module/opensource/opensource.service.ts | 23 +++++++++++-------- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/server/src/module/opensource/opensource.routes.ts b/server/src/module/opensource/opensource.routes.ts index a52a9f0d9..e27f4ffd2 100644 --- a/server/src/module/opensource/opensource.routes.ts +++ b/server/src/module/opensource/opensource.routes.ts @@ -42,23 +42,22 @@ opensourceRouter.get("/", async (req, res, next) => { if (language) where["language"] = { equals: language, mode: "insensitive" }; if (difficulty) where["difficulty"] = difficulty; if (domain) where["domain"] = domain; - if (search) { - // Prisma's scalar-list filters can't do case-insensitive substring match - // on array elements, so resolve tag matches via a raw ILIKE-on-unnest - // subquery and merge the matching ids into the OR clause. + if (search?.trim()) { + const s = search.trim(); + const tagMatches = await prisma.$queryRaw>` SELECT id FROM "opensourceRepo" WHERE EXISTS ( - SELECT 1 FROM unnest(tags) AS t WHERE t ILIKE ${`%${search}%`} + SELECT 1 FROM unnest(tags) AS t WHERE t ILIKE ${`%${s}%`} ) `; const tagMatchIds = tagMatches.map((r) => r.id); - + where["OR"] = [ - { name: { contains: search, mode: "insensitive" } }, - { owner: { contains: search, mode: "insensitive" } }, - { description: { contains: search, mode: "insensitive" } }, - { language: { contains: search, mode: "insensitive" } }, + { name: { contains: s, mode: "insensitive" } }, + { owner: { contains: s, mode: "insensitive" } }, + { description: { contains: s, mode: "insensitive" } }, + { language: { contains: s, mode: "insensitive" } }, ...(tagMatchIds.length > 0 ? [{ id: { in: tagMatchIds } }] : []), ]; } diff --git a/server/src/module/opensource/opensource.service.ts b/server/src/module/opensource/opensource.service.ts index b7ce1d6bf..5a2af96a5 100644 --- a/server/src/module/opensource/opensource.service.ts +++ b/server/src/module/opensource/opensource.service.ts @@ -21,12 +21,15 @@ export class OpensourceService { if (language) where.language = language; if (difficulty) where.difficulty = difficulty; if (domain) where.domain = domain; - if (search) { + + if (search?.trim()) { + const s = search.trim(); + where.OR = [ - { name: { contains: search, mode: "insensitive" } }, - { owner: { contains: search, mode: "insensitive" } }, - { description: { contains: search, mode: "insensitive" } }, - { tags: { hasSome: [search] } }, + { name: { contains: s, mode: "insensitive" } }, + { owner: { contains: s, mode: "insensitive" } }, + { description: { contains: s, mode: "insensitive" } }, + { tags: { hasSome: [s] } }, ]; } @@ -59,10 +62,12 @@ export class OpensourceService { const where: any = {}; - if (search) { + if (search?.trim()) { + const s = search.trim(); + where.OR = [ - { name: { contains: search, mode: "insensitive" } }, - { description: { contains: search, mode: "insensitive" } }, + { name: { contains: s, mode: "insensitive" } }, + { description: { contains: s, mode: "insensitive" } }, ]; } @@ -95,4 +100,4 @@ export class OpensourceService { totalPages: Math.ceil(total / limit), }; } -} +} \ No newline at end of file From fe036cf086099c4f25bf453f9aa3acab8aeccfef Mon Sep 17 00:00:00 2001 From: Mayank Singh Rawat Date: Fri, 5 Jun 2026 09:25:35 +0530 Subject: [PATCH 2/5] fix: trim search query before database lookup --- .../module/opensource/opensource.service.ts | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/server/src/module/opensource/opensource.service.ts b/server/src/module/opensource/opensource.service.ts index 5a2af96a5..a2a337a19 100644 --- a/server/src/module/opensource/opensource.service.ts +++ b/server/src/module/opensource/opensource.service.ts @@ -21,15 +21,12 @@ export class OpensourceService { if (language) where.language = language; if (difficulty) where.difficulty = difficulty; if (domain) where.domain = domain; - - if (search?.trim()) { - const s = search.trim(); - + if (search) { where.OR = [ - { name: { contains: s, mode: "insensitive" } }, - { owner: { contains: s, mode: "insensitive" } }, - { description: { contains: s, mode: "insensitive" } }, - { tags: { hasSome: [s] } }, + { name: { contains: search, mode: "insensitive" } }, + { owner: { contains: search, mode: "insensitive" } }, + { description: { contains: search, mode: "insensitive" } }, + { tags: { hasSome: [search] } }, ]; } @@ -62,12 +59,12 @@ export class OpensourceService { const where: any = {}; - if (search?.trim()) { - const s = search.trim(); + const trimmedSearch = search?.trim(); + if (trimmedSearch) { where.OR = [ - { name: { contains: s, mode: "insensitive" } }, - { description: { contains: s, mode: "insensitive" } }, + { name: { contains: trimmedSearch, mode: "insensitive" } }, + { description: { contains: trimmedSearch, mode: "insensitive" } }, ]; } @@ -100,4 +97,4 @@ export class OpensourceService { totalPages: Math.ceil(total / limit), }; } -} \ No newline at end of file +} From 88d06dfb2449b8ef68aebf1ea75d1539381e99d3 Mon Sep 17 00:00:00 2001 From: Mayank Singh Rawat Date: Fri, 5 Jun 2026 09:36:54 +0530 Subject: [PATCH 3/5] fix: use trimmed search value in filters --- .../module/opensource/opensource.service.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/server/src/module/opensource/opensource.service.ts b/server/src/module/opensource/opensource.service.ts index 7a410ca0d..b93871e60 100644 --- a/server/src/module/opensource/opensource.service.ts +++ b/server/src/module/opensource/opensource.service.ts @@ -25,23 +25,23 @@ export class OpensourceService { if (difficulty) where["difficulty"] = difficulty; if (domain) where["domain"] = domain; - if (search) { - // Prisma's scalar-list filters can't do case-insensitive substring match - // on array elements, so resolve tag matches via a raw ILIKE-on-unnest - // subquery and merge the matching ids into the OR clause. + const trimmedSearch = search?.trim(); + + if (trimmedSearch) { const tagMatches = await prisma.$queryRaw>` SELECT id FROM "opensourceRepo" WHERE EXISTS ( - SELECT 1 FROM unnest(tags) AS t WHERE t ILIKE ${`%${search}%`} + SELECT 1 FROM unnest(tags) AS t WHERE t ILIKE ${`%${trimmedSearch}%`} ) `; + const tagMatchIds = tagMatches.map((r) => r.id); - + where["OR"] = [ - { name: { contains: search, mode: "insensitive" } }, - { owner: { contains: search, mode: "insensitive" } }, - { description: { contains: search, mode: "insensitive" } }, - { language: { contains: search, mode: "insensitive" } }, + { name: { contains: trimmedSearch, mode: "insensitive" } }, + { owner: { contains: trimmedSearch, mode: "insensitive" } }, + { description: { contains: trimmedSearch, mode: "insensitive" } }, + { language: { contains: trimmedSearch, mode: "insensitive" } }, ...(tagMatchIds.length > 0 ? [{ id: { in: tagMatchIds } }] : []), ]; } From b2625716c300213d15d9a69a383e4c5c521ee57b Mon Sep 17 00:00:00 2001 From: Mayank Singh Rawat Date: Fri, 5 Jun 2026 18:32:04 +0530 Subject: [PATCH 4/5] fix: resolve merge conflicts --- .../module/opensource/opensource.service.ts | 35 ++++++------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/server/src/module/opensource/opensource.service.ts b/server/src/module/opensource/opensource.service.ts index 69f6e6a25..9fca8dffd 100644 --- a/server/src/module/opensource/opensource.service.ts +++ b/server/src/module/opensource/opensource.service.ts @@ -78,18 +78,12 @@ export class OpensourceService { if (language) where["language"] = { equals: language, mode: "insensitive" }; if (difficulty) where["difficulty"] = difficulty; if (domain) where["domain"] = domain; -<<<<<<< HEAD +const trimmedSearch = search?.trim(); - const trimmedSearch = search?.trim(); - - if (trimmedSearch) { -======= - const trimmedSearch = search?.trim(); - if (trimmedSearch) { - // Prisma's scalar-list filters can't do case-insensitive substring match - // on array elements, so resolve tag matches via a raw ILIKE-on-unnest - // subquery and merge the matching ids into the OR clause. ->>>>>>> upstream/main +if (trimmedSearch) { + // Prisma's scalar-list filters can't do case-insensitive substring match + // on array elements, so resolve tag matches via a raw ILIKE-on-unnest + // subquery and merge the matching ids into the OR clause. const tagMatches = await prisma.$queryRaw>` SELECT id FROM "opensourceRepo" WHERE EXISTS ( @@ -98,20 +92,11 @@ export class OpensourceService { `; const tagMatchIds = tagMatches.map((r) => r.id); -<<<<<<< HEAD - - where["OR"] = [ - { name: { contains: trimmedSearch, mode: "insensitive" } }, - { owner: { contains: trimmedSearch, mode: "insensitive" } }, - { description: { contains: trimmedSearch, mode: "insensitive" } }, - { language: { contains: trimmedSearch, mode: "insensitive" } }, -======= - where["OR"] = [ - { name: { contains: trimmedSearch, mode: "insensitive" } }, - { owner: { contains: trimmedSearch, mode: "insensitive" } }, - { description: { contains: search, mode: "insensitive" } }, - { language: { contains: search, mode: "insensitive" } }, ->>>>>>> upstream/main +where["OR"] = [ + { name: { contains: trimmedSearch, mode: "insensitive" } }, + { owner: { contains: trimmedSearch, mode: "insensitive" } }, + { description: { contains: trimmedSearch, mode: "insensitive" } }, + { language: { contains: trimmedSearch, mode: "insensitive" } }, ...(tagMatchIds.length > 0 ? [{ id: { in: tagMatchIds } }] : []), ]; } From 13895fd64d7e3062f38e0b60948619c0ce740a8b Mon Sep 17 00:00:00 2001 From: Mayank Singh Rawat Date: Fri, 5 Jun 2026 19:16:27 +0530 Subject: [PATCH 5/5] fix(recruiter): add notes character limit and counter --- .../module/opensource/opensource.routes.ts | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/server/src/module/opensource/opensource.routes.ts b/server/src/module/opensource/opensource.routes.ts index 4de5a3854..1db7fb98a 100644 --- a/server/src/module/opensource/opensource.routes.ts +++ b/server/src/module/opensource/opensource.routes.ts @@ -1,9 +1,5 @@ -<<<<<<< HEAD import { Router } from "express"; -======= -import { Router } from "express"; import { prisma } from "../../database/db.js"; ->>>>>>> upstream/main import { OpensourceController } from "./opensource.controller.js"; import { authMiddleware } from "../../middleware/auth.middleware.js"; import { requireRole } from "../../middleware/role.middleware.js"; @@ -25,27 +21,6 @@ opensourceRouter.get("/languages", (req, res, next) => controller.getLanguages(r // Get GSoC organizations opensourceRouter.get("/gsoc/orgs", (req, res, next) => controller.getGsocOrgs(req, res, next)); -<<<<<<< HEAD -======= -// ─── Student Progress Tracking ───────────────────────────────── -// NOTE: must be before /:id to avoid route conflicts - -opensourceRouter.get( - "/first-pr/progress", - authMiddleware, - requireRole("STUDENT"), - (req, res, next) => controller.getFirstPrProgress(req, res, next), -); - -opensourceRouter.patch( - "/first-pr/progress", - authMiddleware, - requireRole("STUDENT"), - (req, res, next) => controller.patchFirstPrProgress(req, res, next), -); - -// ─── Repo Requests (Student-authenticated) ───────────────────── ->>>>>>> upstream/main // NOTE: these must be registered BEFORE /:id to avoid route conflicts opensourceRouter.post("/requests", authMiddleware, requireRole("STUDENT"), (req, res, next) => @@ -88,6 +63,13 @@ opensourceRouter.get("/analytics/trend", authMiddleware, requireRole("STUDENT"), controller.getStudentContributionTrend(req, res, next), ); +opensourceRouter.get("/first-pr/progress", authMiddleware, requireRole("STUDENT"), (req, res, next) => + controller.getFirstPrProgress(req, res, next), +); + +opensourceRouter.patch("/first-pr/progress", authMiddleware, requireRole("STUDENT"), (req, res, next) => + controller.patchFirstPrProgress(req, res, next), +); // ─── Admin: Manage Repo Requests ─────────────────────────────── opensourceRouter.get("/requests/all", authMiddleware, requireRole("ADMIN"), (req, res, next) =>