diff --git a/package-lock.json b/package-lock.json index 157a9a0..3cb3961 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2064,23 +2064,27 @@ } }, "node_modules/body-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", - "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", + "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", - "debug": "^4.4.0", + "debug": "^4.4.3", "http-errors": "^2.0.0", - "iconv-lite": "^0.6.3", + "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.0", - "raw-body": "^3.0.0", - "type-is": "^2.0.0" + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/bowser": { @@ -2747,15 +2751,19 @@ } }, "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", + "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/inherits": { @@ -2823,12 +2831,12 @@ } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, @@ -2968,9 +2976,9 @@ } }, "node_modules/nodemailer": { - "version": "7.0.10", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.10.tgz", - "integrity": "sha512-Us/Se1WtT0ylXgNFfyFSx4LElllVLJXQjWi2Xz17xWw7amDKO2MLtFnVp1WACy7GkVGs+oBlRopVNUzlrGSw1w==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.12.tgz", + "integrity": "sha512-H+rnK5bX2Pi/6ms3sN4/jRQvYSMltV6vqup/0SFOrxYYY/qoNvhXPlYq3e+Pm9RFJRwrMGbMIwi81M4dxpomhA==", "license": "MIT-0", "engines": { "node": ">=6.0.0" diff --git a/src/routes/search/search.service.ts b/src/routes/search/search.service.ts index d5950d1..cb273ac 100644 --- a/src/routes/search/search.service.ts +++ b/src/routes/search/search.service.ts @@ -120,15 +120,26 @@ export class SearchService { const { tokens } = tokenize(q); + // Users visibility rules + const usersWhere: any = { + OR: [ + { firstName: { contains: q, mode: "insensitive" } }, + { lastName: { contains: q, mode: "insensitive" } }, + { email: { contains: q, mode: "insensitive" } }, + { title: { contains: q, mode: "insensitive" } }, + ], + }; + + if (requesterRole === Role.ADMIN) { + // Admins: can search ONLY normal users (no managers/admins) + usersWhere.AND = [{ role: Role.USER }]; + } else if (requesterRole === Role.MANAGER) { + // Managers: can search admins, managers, and normal users + usersWhere.AND = [{ role: { in: [Role.ADMIN, Role.MANAGER, Role.USER] } }]; + } + const usersCandidates = await prisma.user.findMany({ - where: { - OR: [ - { firstName: { contains: q, mode: "insensitive" } }, - { lastName: { contains: q, mode: "insensitive" } }, - { email: { contains: q, mode: "insensitive" } }, - { title: { contains: q, mode: "insensitive" } }, - ], - }, + where: usersWhere, select: { id: true, firstName: true, @@ -148,16 +159,7 @@ export class SearchService { ], }; - if (requesterRole === Role.MANAGER && requesterId) { - todoWhere.AND = [ - { - OR: [ - { assignees: { some: { id: requesterId } } }, - { assignees: { some: { managerId: requesterId } } }, - ], - }, - ]; - } else if (requesterRole === Role.ADMIN && requesterId) { + if (requesterRole === Role.ADMIN && requesterId) { todoWhere.AND = [{ assignees: { some: { id: requesterId } } }]; } @@ -236,15 +238,26 @@ export class SearchService { const { tokens } = tokenize(q); + // Users visibility rules + const usersWhereFull: any = { + OR: [ + { firstName: { contains: q, mode: "insensitive" } }, + { lastName: { contains: q, mode: "insensitive" } }, + { email: { contains: q, mode: "insensitive" } }, + { title: { contains: q, mode: "insensitive" } }, + ], + }; + + if (requesterRole === Role.ADMIN) { + // Admins: can search ONLY normal users (no managers/admins) + usersWhereFull.AND = [{ role: Role.USER }]; + } else if (requesterRole === Role.MANAGER) { + // Managers: can search admins, managers, and normal users + usersWhereFull.AND = [{ role: { in: [Role.ADMIN, Role.MANAGER, Role.USER] } }]; + } + const userCandidates = await prisma.user.findMany({ - where: { - OR: [ - { firstName: { contains: q, mode: "insensitive" } }, - { lastName: { contains: q, mode: "insensitive" } }, - { email: { contains: q, mode: "insensitive" } }, - { title: { contains: q, mode: "insensitive" } }, - ], - }, + where: usersWhereFull, select: { id: true, firstName: true, @@ -265,16 +278,7 @@ export class SearchService { { task: { contains: q, mode: "insensitive" } }, ], }; - if (requesterRole === Role.MANAGER && requesterId) { - todoWhere.AND = [ - { - OR: [ - { assignees: { some: { id: requesterId } } }, - { assignees: { some: { managerId: requesterId } } }, - ], - }, - ]; - } else if (requesterRole === Role.ADMIN && requesterId) { + if (requesterRole === Role.ADMIN && requesterId) { todoWhere.AND = [{ assignees: { some: { id: requesterId } } }]; }