From 5186d24fe1a517f1b6ed771483ce5cdb88466adc Mon Sep 17 00:00:00 2001 From: jose-carlos-sousa <139002032+jose-carlos-sousa@users.noreply.github.com> Date: Wed, 24 Apr 2024 17:46:45 +0100 Subject: [PATCH 1/5] basic model --- src/models/CV.js | 64 ++++++++++++++++++++++++++++++++++++++ src/models/constants/CV.js | 37 ++++++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 src/models/CV.js create mode 100644 src/models/constants/CV.js diff --git a/src/models/CV.js b/src/models/CV.js new file mode 100644 index 00000000..d80f1994 --- /dev/null +++ b/src/models/CV.js @@ -0,0 +1,64 @@ +import mongoose from "mongoose"; +import CVconstants from "./constants/CV.js"; + +const { Schema } = mongoose; + +const CVSchema = new Schema({ + projects: [{ + type: { + name: { + type: String, + required: true, + maxlength: CVconstants.projectName.max_length, + minlength: CVconstants.projectName.min_length + }, + isExternal: { type: Boolean, default: false } // Default to internal project + } + }], + languages: [{ + language: { + type: String, + required: true, + maxlength: CVconstants.language.max_length, + minlength: CVconstants.language.min_length, + }, + level: { + type: String, + enum: ["Beginner", "Intermediate", "Advanced", "Fluent"], + default: "Intermediate" + } + }], + skills: [{ + type: String, + maxlength: CVconstants.skills.max_length, + minlength: CVconstants.skills.min_length + }], + achievements: { + type: String, + maxlength: CVconstants.achievements.max_length, + minlength: CVconstants.achievement.min_length + }, + events: { + type: String, + maxlength: CVconstants.events.max_length, + minlength: CVconstants.events.min_length + }, + cvFileUrl: { + type: String, + maxlength: CVconstants.cvFileUrl.max_length, + minlength: CVconstants.cvFileUrl.min_length + }, + personalWebsite: { + type: String, + maxlength: CVconstants.personalWebsite.max_length, + minlength: CVconstants.personalWebsite.min_length, + default: null // Assuming it's optional, set default to null + } +}); + + + +const CV = mongoose.model("CV", CVSchema); + + +export default CV; diff --git a/src/models/constants/CV.js b/src/models/constants/CV.js new file mode 100644 index 00000000..254b185e --- /dev/null +++ b/src/models/constants/CV.js @@ -0,0 +1,37 @@ +export default Object.freeze({ + projectName: { + min_length: 2, + max_length: 50, + }, + language: { + min_length: 2, + max_length: 50, + }, + skills: { + min_length: 2, + max_length: 50, + }, + achievements: { + min_length: 2, + max_length: 200, + }, + cvFileUrl: { + min_length: 2, + max_length: 200, + }, + personalWebsite: { + min_length: 2, + max_length: 200, + }, + personalizedFields: [{ + fieldName: { + type: String, + required: true, + maxlength: 100, // Adjust the max length as needed + }, + value: { + type: String, + maxlength: 255, // Adjust the max length as needed + }, + }], +}); From 299e9d360a70b2f155b35095137e8d5286e8c342 Mon Sep 17 00:00:00 2001 From: jose-carlos-sousa <139002032+jose-carlos-sousa@users.noreply.github.com> Date: Wed, 24 Apr 2024 17:56:59 +0100 Subject: [PATCH 2/5] made languages mandatory --- src/models/CV.js | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/models/CV.js b/src/models/CV.js index d80f1994..38c547a5 100644 --- a/src/models/CV.js +++ b/src/models/CV.js @@ -2,7 +2,6 @@ import mongoose from "mongoose"; import CVconstants from "./constants/CV.js"; const { Schema } = mongoose; - const CVSchema = new Schema({ projects: [{ type: { @@ -15,19 +14,23 @@ const CVSchema = new Schema({ isExternal: { type: Boolean, default: false } // Default to internal project } }], - languages: [{ - language: { - type: String, - required: true, - maxlength: CVconstants.language.max_length, - minlength: CVconstants.language.min_length, - }, - level: { - type: String, - enum: ["Beginner", "Intermediate", "Advanced", "Fluent"], - default: "Intermediate" - } - }], + languages: { + type: [{ + language: { + type: String, + required: true, + maxlength: CVconstants.language.max_length, + minlength: CVconstants.language.min_length, + }, + level: { + type: String, + required: true, + enum: ["Beginner", "Intermediate", "Advanced", "Fluent"], + default: "Intermediate" + } + }], + validate: [arrayLengthValidator, "At least one language must be provided"] + }, skills: [{ type: String, maxlength: CVconstants.skills.max_length, @@ -36,26 +39,32 @@ const CVSchema = new Schema({ achievements: { type: String, maxlength: CVconstants.achievements.max_length, - minlength: CVconstants.achievement.min_length + minlength: CVconstants.achievement.min_length, + default: null // Make it optional, set default to null }, events: { type: String, maxlength: CVconstants.events.max_length, - minlength: CVconstants.events.min_length + minlength: CVconstants.events.min_length, + default: null // Make it optional, set default to null }, cvFileUrl: { type: String, maxlength: CVconstants.cvFileUrl.max_length, - minlength: CVconstants.cvFileUrl.min_length + minlength: CVconstants.cvFileUrl.min_length, + default: null // Make it optional, set default to null }, personalWebsite: { type: String, maxlength: CVconstants.personalWebsite.max_length, minlength: CVconstants.personalWebsite.min_length, - default: null // Assuming it's optional, set default to null + default: null // Make it optional, set default to null } }); +function arrayLengthValidator(arr) { + return arr && arr.length >= 1; +} const CV = mongoose.model("CV", CVSchema); From d7c60720104d5923ab60aa871e60e27e68c07e87 Mon Sep 17 00:00:00 2001 From: jose-carlos-sousa <139002032+jose-carlos-sousa@users.noreply.github.com> Date: Wed, 8 May 2024 11:14:24 +0100 Subject: [PATCH 3/5] Implemented basic required and bound testing --- src/models/CV.js | 4 +- src/models/constants/CV.js | 4 ++ test/cv_schema.js | 107 +++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 test/cv_schema.js diff --git a/src/models/CV.js b/src/models/CV.js index 38c547a5..88d683cb 100644 --- a/src/models/CV.js +++ b/src/models/CV.js @@ -26,9 +26,9 @@ const CVSchema = new Schema({ type: String, required: true, enum: ["Beginner", "Intermediate", "Advanced", "Fluent"], - default: "Intermediate" } }], + required: true, validate: [arrayLengthValidator, "At least one language must be provided"] }, skills: [{ @@ -39,7 +39,7 @@ const CVSchema = new Schema({ achievements: { type: String, maxlength: CVconstants.achievements.max_length, - minlength: CVconstants.achievement.min_length, + minlength: CVconstants.achievements.min_length, default: null // Make it optional, set default to null }, events: { diff --git a/src/models/constants/CV.js b/src/models/constants/CV.js index 254b185e..f356d3f0 100644 --- a/src/models/constants/CV.js +++ b/src/models/constants/CV.js @@ -15,6 +15,10 @@ export default Object.freeze({ min_length: 2, max_length: 200, }, + events: { + min_length: 2, + max_length: 200, + }, cvFileUrl: { min_length: 2, max_length: 200, diff --git a/test/cv_schema.js b/test/cv_schema.js new file mode 100644 index 00000000..c1e14042 --- /dev/null +++ b/test/cv_schema.js @@ -0,0 +1,107 @@ +import CV from "../src/models/CV.js"; + + +describe("# CV Schema tests", () => { + describe("Required and bound properties tests", () => { + + test("'cvFileUrl' field is not required", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.projects).toBeUndefined(); + } + }); + + test("'languages' field is required", async () => { + const cv = new CV(); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.languages).toBeDefined(); + expect(err.errors.languages.kind).toBe("user defined"); + expect(err.errors.languages.message).toBe("At least one language must be provided"); + } + }); + + test("'languages' array length must be one or more", async () => { + const cv = new CV({ languages: [] }); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.languages).toBeDefined(); + expect(err.errors.languages.kind).toBe("user defined"); + expect(err.errors.languages.message).toBe("At least one language must be provided"); + } + }); + + test("'languages' array item must have language", async () => { + const cv = new CV({ languages: [{ level: "Advanced" }] }); + try { + await cv.validate(); + } catch (err) { + /* eslint-disable no-alert, no-console */ + console.log("proj err", err); + expect(err.errors["languages.0.language"]).toBeDefined(); + expect(err.errors["languages.0.language"].kind).toBe("required"); + } + }); + + test("'languages' array item must have level", async () => { + const cv = new CV({ languages: [{ language: "English" }] }); + try { + await cv.validate(); + } catch (err) { + expect(err.errors["languages.0.level"]).toBeDefined(); + expect(err.errors["languages.0.level"].kind).toBe("required"); + } + }); + + test("'skills' field is not required", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.skills).toBeUndefined(); + } + }); + + test("'achievements' field", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.achievements).toBeUndefined(); + } + }); + + test("'events' field", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.events).toBeUndefined(); + } + }); + + test("'cvFileUrl' field", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.cvFileUrl).toBeUndefined(); + } + }); + + test("'personalWebsite' field", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.personalWebsite).toBeUndefined(); + } + }); + }); + + +}); From 231889985d93ae70d9f1f2d7acfadd7ad7c1fe67 Mon Sep 17 00:00:00 2001 From: jose-carlos-sousa <139002032+jose-carlos-sousa@users.noreply.github.com> Date: Wed, 22 May 2024 15:49:44 +0100 Subject: [PATCH 4/5] added user id to the cv schema --- src/models/CV.js | 6 +++++- test/cv_schema.js | 10 ++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/models/CV.js b/src/models/CV.js index 88d683cb..adad33a1 100644 --- a/src/models/CV.js +++ b/src/models/CV.js @@ -3,6 +3,10 @@ import CVconstants from "./constants/CV.js"; const { Schema } = mongoose; const CVSchema = new Schema({ + UserId: { + type: Schema.Types.ObjectId, + required: true + }, projects: [{ type: { name: { @@ -11,7 +15,7 @@ const CVSchema = new Schema({ maxlength: CVconstants.projectName.max_length, minlength: CVconstants.projectName.min_length }, - isExternal: { type: Boolean, default: false } // Default to internal project + isExternal: { type: Boolean, default: false } } }], languages: { diff --git a/test/cv_schema.js b/test/cv_schema.js index c1e14042..817d6a1d 100644 --- a/test/cv_schema.js +++ b/test/cv_schema.js @@ -4,6 +4,16 @@ import CV from "../src/models/CV.js"; describe("# CV Schema tests", () => { describe("Required and bound properties tests", () => { + test("'UserId' field is required", async () => { + const cv = new CV(); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.UserId).toBeDefined(); + expect(err.errors.UserId.kind).toBe("required"); + } + }); + test("'cvFileUrl' field is not required", async () => { const cv = new CV({}); try { From d9194e84235f9a95e3037a59bcaff782134b5dc6 Mon Sep 17 00:00:00 2001 From: jose-carlos-sousa <139002032+jose-carlos-sousa@users.noreply.github.com> Date: Wed, 22 May 2024 17:47:21 +0100 Subject: [PATCH 5/5] added optional field and description --- package-lock.json | 146 +++++++++++++++++++++++-------------- src/models/CV.js | 23 ++++-- src/models/constants/CV.js | 12 ++- test/cv_schema.js | 34 +++++++++ 4 files changed, 151 insertions(+), 64 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5d461e75..d5df3977 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3916,11 +3916,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "license": "MIT", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -3928,7 +3929,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -3939,18 +3940,21 @@ }, "node_modules/body-parser/node_modules/debug": { "version": "2.6.9", - "license": "MIT", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dependencies": { "ms": "2.0.0" } }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", - "license": "MIT" + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/body-parser/node_modules/on-finished": { "version": "2.4.1", - "license": "MIT", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { "ee-first": "1.1.1" }, @@ -4070,7 +4074,8 @@ }, "node_modules/bytes": { "version": "3.1.2", - "license": "MIT", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "engines": { "node": ">= 0.8" } @@ -4432,8 +4437,9 @@ "license": "MIT" }, "node_modules/content-type": { - "version": "1.0.4", - "license": "MIT", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -5122,15 +5128,16 @@ } }, "node_modules/express": { - "version": "4.18.2", - "license": "MIT", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -5259,8 +5266,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.5.0", - "license": "MIT", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", "engines": { "node": ">= 0.6" } @@ -5780,7 +5788,8 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", - "license": "MIT", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -5882,9 +5891,9 @@ "license": "ISC" }, "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -6953,11 +6962,9 @@ "license": "MIT" }, "node_modules/minipass": { - "version": "4.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "engines": { "node": ">=8" } @@ -7258,8 +7265,9 @@ "license": "MIT" }, "node_modules/nodemailer": { - "version": "6.8.0", - "license": "MIT", + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", "engines": { "node": ">=6.0.0" } @@ -7782,8 +7790,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "license": "MIT", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -8003,7 +8012,8 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "license": "MIT" + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/saslprep": { "version": "1.0.3", @@ -8424,12 +8434,13 @@ } }, "node_modules/tar": { - "version": "6.1.13", - "license": "ISC", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" @@ -11657,10 +11668,12 @@ } }, "body-parser": { - "version": "1.20.1", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "requires": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -11668,22 +11681,28 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, "dependencies": { "debug": { "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "requires": { "ms": "2.0.0" } }, "ms": { - "version": "2.0.0" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "on-finished": { "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { "ee-first": "1.1.1" } @@ -11754,7 +11773,9 @@ } }, "bytes": { - "version": "3.1.2" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" }, "call-bind": { "version": "1.0.2", @@ -11969,7 +11990,9 @@ } }, "content-type": { - "version": "1.0.4" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" }, "convert-source-map": { "version": "1.7.0", @@ -12384,14 +12407,16 @@ } }, "express": { - "version": "4.18.2", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -12420,7 +12445,9 @@ }, "dependencies": { "cookie": { - "version": "0.5.0" + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" }, "debug": { "version": "2.6.9", @@ -12796,6 +12823,8 @@ }, "iconv-lite": { "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "requires": { "safer-buffer": ">= 2.1.2 < 3" } @@ -12850,9 +12879,9 @@ "version": "2.0.4" }, "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "ipaddr.js": { "version": "1.9.1" @@ -13567,10 +13596,9 @@ "version": "1.2.6" }, "minipass": { - "version": "4.0.0", - "requires": { - "yallist": "^4.0.0" - } + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" }, "minizlib": { "version": "2.1.2", @@ -13760,7 +13788,9 @@ "version": "2.0.7" }, "nodemailer": { - "version": "6.8.0" + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==" }, "nodemailer-express-handlebars": { "version": "5.0.0", @@ -14064,7 +14094,9 @@ } }, "raw-body": { - "version": "2.5.1", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -14199,7 +14231,9 @@ "version": "5.1.2" }, "safer-buffer": { - "version": "2.1.2" + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "saslprep": { "version": "1.0.3", @@ -14479,11 +14513,13 @@ "dev": true }, "tar": { - "version": "6.1.13", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" diff --git a/src/models/CV.js b/src/models/CV.js index adad33a1..ca92dfe9 100644 --- a/src/models/CV.js +++ b/src/models/CV.js @@ -7,6 +7,11 @@ const CVSchema = new Schema({ type: Schema.Types.ObjectId, required: true }, + description: { + type: String, + maxlength: CVconstants.description.max_length, + minlength: CVconstants.description.min_length, + }, projects: [{ type: { name: { @@ -44,26 +49,34 @@ const CVSchema = new Schema({ type: String, maxlength: CVconstants.achievements.max_length, minlength: CVconstants.achievements.min_length, - default: null // Make it optional, set default to null }, events: { type: String, maxlength: CVconstants.events.max_length, minlength: CVconstants.events.min_length, - default: null // Make it optional, set default to null }, cvFileUrl: { type: String, maxlength: CVconstants.cvFileUrl.max_length, minlength: CVconstants.cvFileUrl.min_length, - default: null // Make it optional, set default to null }, personalWebsite: { type: String, maxlength: CVconstants.personalWebsite.max_length, minlength: CVconstants.personalWebsite.min_length, - default: null // Make it optional, set default to null - } + }, + personalizedFields: [{ + fieldName: { + type: String, + required: true, + maxlength: CVconstants.personalizedFields.fieldName.max_length, + }, + value: { + type: String, + required: true, + maxlength: CVconstants.personalizedFields.value.max_length, + }, + }], }); function arrayLengthValidator(arr) { diff --git a/src/models/constants/CV.js b/src/models/constants/CV.js index f356d3f0..4e95df33 100644 --- a/src/models/constants/CV.js +++ b/src/models/constants/CV.js @@ -3,6 +3,10 @@ export default Object.freeze({ min_length: 2, max_length: 50, }, + description: { + min_length: 2, + max_length: 200, + }, language: { min_length: 2, max_length: 50, @@ -27,15 +31,15 @@ export default Object.freeze({ min_length: 2, max_length: 200, }, - personalizedFields: [{ + personalizedFields: { fieldName: { type: String, required: true, - maxlength: 100, // Adjust the max length as needed + maxlength: 100, }, value: { type: String, - maxlength: 255, // Adjust the max length as needed + maxlength: 300, }, - }], + }, }); diff --git a/test/cv_schema.js b/test/cv_schema.js index 817d6a1d..6b8cb8fe 100644 --- a/test/cv_schema.js +++ b/test/cv_schema.js @@ -111,6 +111,40 @@ describe("# CV Schema tests", () => { expect(err.errors.personalWebsite).toBeUndefined(); } }); + test("'personalizedFields' field", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.personalizedFields).toBeUndefined(); + } + }); + test("'personalizedFields' array item must have fieldName", async () => { + const cv = new CV({ personalizedFields: [{ value: "value" }] }); + try { + await cv.validate(); + } catch (err) { + expect(err.errors["personalizedFields.0.fieldName"]).toBeDefined(); + expect(err.errors["personalizedFields.0.fieldName"].kind).toBe("required"); + } + }); + test("'personalizedFields' array item must have value", async () => { + const cv = new CV({ personalizedFields: [{ fieldName: "fieldName" }] }); + try { + await cv.validate(); + } catch (err) { + expect(err.errors["personalizedFields.0.value"]).toBeDefined(); + expect(err.errors["personalizedFields.0.value"].kind).toBe("required"); + } + }); + test("'description' ", async () => { + const cv = new CV({}); + try { + await cv.validate(); + } catch (err) { + expect(err.errors.description).toBeUndefined(); + } + }); });