diff --git a/README.md b/README.md index 8100ba86..fe52111c 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,10 @@ NEXT_PUBLIC_BASE_URL=http://localhost:3000 ### Launch the app Then install dependencies using `npm install`, run the dev server using `npm run dev` + +### Generate seeds + +If you want to generate random seed data, you can use the hasura console to export the Skill table to JSON +Then move it to `hasura/seeds/Skill.json` +You can now run `npm run seeds:generate` +And `npm run seeds:apply` to apply the random data to the database diff --git a/hasura/seeds/.gitignore b/hasura/seeds/.gitignore new file mode 100644 index 00000000..a6a1fa4d --- /dev/null +++ b/hasura/seeds/.gitignore @@ -0,0 +1,2 @@ +Skill.json +seeds.sql \ No newline at end of file diff --git a/hasura/seeds/Agency.json b/hasura/seeds/Agency.json new file mode 100644 index 00000000..35e88fa6 --- /dev/null +++ b/hasura/seeds/Agency.json @@ -0,0 +1,32 @@ +[ + { + "name": "Paris" + }, + { + "name": "Nantes" + }, + { + "name": "Singapore" + }, + { + "name": "Bordeaux" + }, + { + "name": "Brest" + }, + { + "name": "Montreal" + }, + { + "name": "Grenoble" + }, + { + "name": "Lyon" + }, + { + "name": "Rennes" + }, + { + "name": "Lille" + } +] \ No newline at end of file diff --git a/hasura/seeds/Category.json b/hasura/seeds/Category.json new file mode 100644 index 00000000..96bfaa31 --- /dev/null +++ b/hasura/seeds/Category.json @@ -0,0 +1,34 @@ +[ + { + "index": 1, + "color": "yellow", + "label": "languages-and-frameworks", + "x": "left", + "y": "top", + "id": "89780de3-4a4c-40c2-bcdf-b5d15a48437a" + }, + { + "index": 2, + "color": "violet", + "label": "platforms", + "x": "right", + "y": "top", + "id": "06420261-3e78-4a91-bc6a-1a52cad5d6a1" + }, + { + "index": 3, + "color": "blue", + "label": "tools", + "x": "left", + "y": "bot", + "id": "c3341edb-3c1f-4e3d-bf89-8e795eb13690" + }, + { + "index": 4, + "color": "cyan", + "label": "technics-and-methods", + "x": "right", + "y": "bot", + "id": "89f5e9a5-5ce6-416c-bed9-dd736546aa7f" + } +] \ No newline at end of file diff --git a/hasura/seeds/Topic.json b/hasura/seeds/Topic.json new file mode 100644 index 00000000..e8cecf54 --- /dev/null +++ b/hasura/seeds/Topic.json @@ -0,0 +1,58 @@ +[ + { + "name": "Frontend", + "id": "71c8f42c-7182-444d-8133-3a3a52ae7912" + }, + { + "name": "Backend", + "id": "16198ae7-40bb-4fcd-ae5d-ce371902dce2" + }, + { + "name": "Agilité", + "id": "5a83e55d-22f2-428a-a5e2-effade6b6be5" + }, + { + "name": "Maker", + "id": "b53a5cdb-6269-4965-ae5b-f42c9611664f" + }, + { + "name": "Réseau", + "id": "817e3dae-01da-446a-920b-a3a5a9f57bea" + }, + { + "name": "Web", + "id": "7e8e6f07-7844-4c1f-aa91-1dda49555ee3" + }, + { + "name": "Security", + "id": "eb4edee0-9351-4fce-b04f-acbee63634b0" + }, + { + "name": "Microservices", + "id": "c42d872f-227e-49ce-8a97-2af8aa021fbd" + }, + { + "name": "Network", + "id": "6be68073-0f12-42bc-9835-07f8e81ea4a3" + }, + { + "name": "Ops", + "id": "2117fd9e-bda8-4b0a-b1f1-6ea68bca3443" + }, + { + "name": "DevOps", + "id": "7ee06efb-f337-4541-b160-10e35cd5b574" + }, + { + "name": "IA", + "id": "5451823f-965c-40e7-85db-05ff8c7a370d" + }, + { + "name": "Data", + "id": "fa4af642-a890-4966-9224-2c607807ef68" + }, + { + "name": "Mobile", + "id": "c80dbcaa-b6d5-42fb-b375-0bb3146fcbbe" + } +] \ No newline at end of file diff --git a/hasura/seeds/seedscript.ts b/hasura/seeds/seedscript.ts new file mode 100644 index 00000000..bd99f8ad --- /dev/null +++ b/hasura/seeds/seedscript.ts @@ -0,0 +1,141 @@ +import { writeFile } from "fs/promises"; +import { datatype, date, image, name, random } from "faker"; +import newJsonSql from "json-sql"; + +const jsonSql = newJsonSql(); +jsonSql.configure({ + dialect: "postgresql", + wrappedIdentifiers: true, + separatedValues: false, +}); + +type Agency = { name: string }; +type Skill = { id: string; name: string; categoryId: string }; + +const agencies: Agency[] = require("./Agency.json"); +const categories = require("./Category.json"); +const skills: Skill[] = require("./Skill.json"); +const topics = require("./Topic.json"); + +type User = { + email: string; + name: string; + picture: string; +}; + +type UserAgency = { + userEmail: string; + agency: string; + created_at: string; +}; + +type UserSkillDesire = { + userEmail: string; + skillId: string; + skillLevel: number; + desireLevel: number; + created_at: string; +}; + +const config = { + nbUser: 500, + nbSkillEntriesPerUser: 30, + dateStart: "2020/01/01", + dateEnd: "2021/12/30", +}; + +const users: User[] = []; +const userSkillDesires: UserSkillDesire[] = []; +const userAgencies: UserAgency[] = []; + +const generateUniqueDate = ( + source: UserSkillDesire[], + userEmail: string, + skillid: string +) => { + let proposedDate = ""; + do { + proposedDate = date + .between(config.dateStart, config.dateEnd) + .toISOString() + .split("T")[0]; + } while ( + source.find( + (row) => + row.userEmail === userEmail && + row.skillId === skillid && + row.created_at === proposedDate + ) + ); + return proposedDate; +}; + +const generateUser = (): User => { + const firstName = name.firstName().replace("'", ""); + const lastName = name.lastName().replace("'", ""); + return { + email: `${firstName.toLowerCase()}.${lastName.toLowerCase()}@zenika.com`, + name: `${firstName} ${lastName}`, + picture: image.avatar(), + }; +}; + +const generateUserAgency = (userEmail: string): UserAgency => { + return { + userEmail, + agency: random.arrayElement(agencies).name, + created_at: "2020/01/01", + }; +}; + +const generateUserSkillAndDesire = ( + userEmail: string +): UserSkillDesire => { + const skillId = + skills[datatype.number({ min: 0, max: skills.length - 1 })].id; + const created_at = generateUniqueDate(userSkillDesires, userEmail, skillId); + return { + userEmail, + skillId, + skillLevel: datatype.number({ min: 1, max: 5 }), + desireLevel: datatype.number({ min: 1, max: 5 }), + created_at, + }; +}; + +for (let i = 0; i < config.nbUser; ++i) { + const user = generateUser(); + users.push(user); + userAgencies.push(generateUserAgency(user.email)); + for (let k = 0; k < config.nbSkillEntriesPerUser; ++k) { + const generatedSkillAndDesire = generateUserSkillAndDesire(user.email); + userSkillDesires.push(generatedSkillAndDesire); + } +} + +const userInsertQuery = jsonSql.build({ + type: "insert", + table: "User", + values: users, +}); + +const userAgenciesInsertQuery = jsonSql.build({ + type: "insert", + table: "UserAgency", + values: userAgencies, +}); + +const userSkillsInsertQuery = jsonSql.build({ + type: "insert", + table: "UserSkillDesire", + values: userSkillDesires, +}); + +const result = `${userInsertQuery.query} +${userAgenciesInsertQuery.query} +${userSkillsInsertQuery.query}`; + +(async () => { + await writeFile("./hasura/seeds/seeds.sql", result); + console.log("Seeds succesfully generated into hasura/seeds/seeds.sql file"); +})(); diff --git a/next.config.js b/next.config.js index a4f6deba..9338e1be 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,7 @@ const runtimeCaching = require("next-pwa/cache"); module.exports = withPWA({ images: { - domains: ["lh3.googleusercontent.com"], + domains: ["lh3.googleusercontent.com", "cdn.fakercloud.com"], }, pwa: { dest: "public", diff --git a/package-lock.json b/package-lock.json index a39c86c5..0084fec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,13 +22,16 @@ "use-debounce": "^6.0.0" }, "devDependencies": { + "@types/faker": "^5.5.6", "@types/node": "^14.14.14", "@types/object-path": "^0.11.0", "@types/react": "^17.0.0", "autoprefixer": "^10.2.5", "ava": "^3.15.0", "cypress": "^6.3.0", + "faker": "^5.5.3", "hasura-cli": "^1.3.3", + "json-sql": "^0.5.0", "postcss": "^8.2.14", "prettier": "^2.2.1", "tailwindcss": "^2.1.2", @@ -1921,6 +1924,12 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, + "node_modules/@types/faker": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.6.tgz", + "integrity": "sha512-UCRj0kLg4sXs2XFVm48OU/wIjyJZkpRkwxhRGVQb5l5GmemkeW22WTz9iiDhYPBUqTzDsIWzhFRuF/4DD5+q2Q==", + "dev": true + }, "node_modules/@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -3764,6 +3773,7 @@ "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", + "fsevents": "~2.1.2", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -4041,6 +4051,7 @@ "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "dependencies": { + "colors": "^1.1.2", "object-assign": "^4.1.0", "string-width": "^4.2.0" }, @@ -6053,6 +6064,12 @@ "node >=0.6.0" ] }, + "node_modules/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -7719,6 +7736,15 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "node_modules/json-sql": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/json-sql/-/json-sql-0.5.0.tgz", + "integrity": "sha512-f2vlEHp8OEZUOm60Vq5gegYJxPLtmDOHJSSaJuzgRtHPQprupEjycYmUbRZwliBUN31fOvvCJhiqVjntVxGqmA==", + "dev": true, + "dependencies": { + "underscore": "1.8.2" + } + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -7744,6 +7770,7 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { + "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -8945,6 +8972,7 @@ "resolve-url-loader": "3.1.2", "sass-loader": "10.0.5", "schema-utils": "2.7.1", + "sharp": "0.26.3", "stream-browserify": "3.0.0", "style-loader": "1.2.1", "styled-jsx": "3.3.2", @@ -11816,6 +11844,9 @@ "version": "2.39.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.39.0.tgz", "integrity": "sha512-+WR3bttcq7zE+BntH09UxaW3bQo3vItuYeLsyk4dL2tuwbeSKJuvwiawyhEnvRdRgrII0Uzk00FpctHO/zB1kw==", + "dependencies": { + "fsevents": "~2.3.1" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -13093,6 +13124,7 @@ "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", + "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -13718,6 +13750,12 @@ "node": ">=4.2.0" } }, + "node_modules/underscore": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.2.tgz", + "integrity": "sha1-ZN8utZCJnelQeC83NRkLpC6/MR0=", + "dev": true + }, "node_modules/unfetch": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", @@ -14128,6 +14166,7 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", + "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -14442,8 +14481,10 @@ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", "dependencies": { + "chokidar": "^3.4.1", "graceful-fs": "^4.1.2", - "neo-async": "^2.5.0" + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" }, "optionalDependencies": { "chokidar": "^3.4.1", @@ -16341,6 +16382,12 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, + "@types/faker": { + "version": "5.5.6", + "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.6.tgz", + "integrity": "sha512-UCRj0kLg4sXs2XFVm48OU/wIjyJZkpRkwxhRGVQb5l5GmemkeW22WTz9iiDhYPBUqTzDsIWzhFRuF/4DD5+q2Q==", + "dev": true + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -19698,6 +19745,12 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, + "faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==", + "dev": true + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -21019,6 +21072,15 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-sql": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/json-sql/-/json-sql-0.5.0.tgz", + "integrity": "sha512-f2vlEHp8OEZUOm60Vq5gegYJxPLtmDOHJSSaJuzgRtHPQprupEjycYmUbRZwliBUN31fOvvCJhiqVjntVxGqmA==", + "dev": true, + "requires": { + "underscore": "1.8.2" + } + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -25702,6 +25764,12 @@ "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", "dev": true }, + "underscore": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.2.tgz", + "integrity": "sha1-ZN8utZCJnelQeC83NRkLpC6/MR0=", + "dev": true + }, "unfetch": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz", diff --git a/package.json b/package.json index 542fcc7e..c4dbd0fc 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,9 @@ "test:integration": "npm run cypress:run", "cypress:open": "cypress open", "cypress:run": "cypress run", - "hasura": "hasura --project ./hasura" + "hasura": "hasura --project ./hasura", + "seeds:generate": "ts-node ./hasura/seeds/seedscript.ts", + "seeds:apply": "npm run hasura seeds apply" }, "dependencies": { "@apollo/client": "^3.3.9", @@ -36,13 +38,16 @@ "use-debounce": "^6.0.0" }, "devDependencies": { + "@types/faker": "^5.5.6", "@types/node": "^14.14.14", "@types/object-path": "^0.11.0", "@types/react": "^17.0.0", "autoprefixer": "^10.2.5", "ava": "^3.15.0", "cypress": "^6.3.0", + "faker": "^5.5.3", "hasura-cli": "^1.3.3", + "json-sql": "^0.5.0", "postcss": "^8.2.14", "prettier": "^2.2.1", "tailwindcss": "^2.1.2",