diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d352420ac80f93a9101b025cceec9e3014b8fb1..683abfea1ec8db4ce91c6eb5fb7df95375fd2c5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,21 @@ **💥 Breaking:** **⚠️ Deprecation:** + +### 🔨 Internal / Developers +- No modifications / Keep major and minors versions in sync with all parts of the project --> +## 3.0.0 (?) + +### ✨ Feature +- Login to Dojo app via Gitlab OAuth +- User access type management + - **student**: default access type for new users + - **teachingStaff**: student access + possibility of creating assignment + - **admin**: teachingStaff access + access to user access management + + ## 2.2.0 (2023-10-16) ### ✨ Feature diff --git a/ExpressAPI/.env.vault b/ExpressAPI/.env.vault index 7e45ae4669f2d45eb5ff0b09d06bfda38a329afb..0fddeea52298fa783288af4b6e389fc290d51817 100644 --- a/ExpressAPI/.env.vault +++ b/ExpressAPI/.env.vault @@ -4,8 +4,8 @@ #/--------------------------------------------------/ # development -DOTENV_VAULT_DEVELOPMENT="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" +DOTENV_VAULT_DEVELOPMENT="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" # production -DOTENV_VAULT_PRODUCTION="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" +DOTENV_VAULT_PRODUCTION="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" diff --git a/ExpressAPI/package-lock.json b/ExpressAPI/package-lock.json index 8f963c7eac7601ac218372bff36cd4a480d1dc0e..820606b932de494ee9fa913b08af03bbe352ebfa 100644 --- a/ExpressAPI/package-lock.json +++ b/ExpressAPI/package-lock.json @@ -1,18 +1,17 @@ { "name": "dojo_backend_api", - "version": "2.2.0", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dojo_backend_api", - "version": "2.2.0", + "version": "3.0.0", "license": "AGPLv3", "dependencies": { "@prisma/client": "^5.1.1", "ajv": "^8.12.0", "axios": "^1.4.0", - "bcryptjs": "^2.4.3", "compression": "^1.7.4", "cors": "^2.8.5", "dotenv": "^16.3.1", @@ -36,7 +35,6 @@ "winston": "^3.8.2" }, "devDependencies": { - "@types/bcryptjs": "^2.4.2", "@types/compression": "^1.7.2", "@types/cors": "^2.8.13", "@types/express": "^4.17.17", @@ -58,9 +56,9 @@ } }, "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", "engines": { "node": ">=0.1.90" } @@ -530,21 +528,21 @@ "dev": true }, "node_modules/@oclif/screen": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.7.tgz", - "integrity": "sha512-jQBPHcMh5rcIPKdqA6xlzioLOmkaVnjg2MVyjMzBKV8hDhLWNSiZqx7NAWXpP70v2LFvGdVoV8BSbK9iID3eHg==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.8.tgz", + "integrity": "sha512-yx6KAqlt3TAHBduS2fMQtJDL2ufIHnDRArrJEOoTTuizxqmjLT+psGYOHpmMl3gvQpFJ11Hs76guUUktzAF9Bg==", "dev": true, "engines": { "node": ">=12.0.0" } }, "node_modules/@prisma/client": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.3.1.tgz", - "integrity": "sha512-ArOKjHwdFZIe1cGU56oIfy7wRuTn0FfZjGuU/AjgEBOQh+4rDkB6nF+AGHP8KaVpkBIiHGPQh3IpwQ3xDMdO0Q==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.4.2.tgz", + "integrity": "sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA==", "hasInstallScript": true, "dependencies": { - "@prisma/engines-version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59" + "@prisma/engines-version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574" }, "engines": { "node": ">=16.13" @@ -559,16 +557,16 @@ } }, "node_modules/@prisma/engines": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.3.1.tgz", - "integrity": "sha512-6QkILNyfeeN67BNEPEtkgh3Xo2tm6D7V+UhrkBbRHqKw9CTaz/vvTP/ROwYSP/3JT2MtIutZm/EnhxUiuOPVDA==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.4.2.tgz", + "integrity": "sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g==", "devOptional": true, "hasInstallScript": true }, "node_modules/@prisma/engines-version": { - "version": "5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.3.1-2.61e140623197a131c2a6189271ffee05a7aa9a59.tgz", - "integrity": "sha512-y5qbUi3ql2Xg7XraqcXEdMHh0MocBfnBzDn5GbV1xk23S3Mq8MGs+VjacTNiBh3dtEdUERCrUUG7Z3QaJ+h79w==" + "version": "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz", + "integrity": "sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA==" }, "node_modules/@tsconfig/node10": { "version": "1.0.9", @@ -594,16 +592,10 @@ "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true }, - "node_modules/@types/bcryptjs": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.4.tgz", - "integrity": "sha512-9wlJI7k5gRyJEC4yrV7DubzNQFTPiykYxUA6lBtsk5NlOfW9oWLJ1HdIA4YtE+6C3i3mTpDQQEosJ2rVZfBWnw==", - "dev": true - }, "node_modules/@types/body-parser": { - "version": "1.19.3", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.3.tgz", - "integrity": "sha512-oyl4jvAfTGX9Bt6Or4H9ni1Z447/tQuxnZsytsCaExKlmJiU8sFgnIBRzJUpKwB5eWn9HuBYlUlVA74q/yN0eQ==", + "version": "1.19.4", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz", + "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==", "dev": true, "dependencies": { "@types/connect": "*", @@ -611,45 +603,45 @@ } }, "node_modules/@types/cli-progress": { - "version": "3.11.3", - "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.3.tgz", - "integrity": "sha512-/+C9xAdVtc+g5yHHkGBThgAA8rYpi5B+2ve3wLtybYj0JHEBs57ivR4x/zGfSsplRnV+psE91Nfin1soNKqz5Q==", + "version": "3.11.4", + "resolved": "https://registry.npmjs.org/@types/cli-progress/-/cli-progress-3.11.4.tgz", + "integrity": "sha512-yufTxeeNCZuEIxx2uebK8lpSAsJM4lvzakm/VxzYhDtqhXCzwH9jpn7nPCxzrROuEbLATqhFq4MIPoG0tlrsvw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/compression": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.3.tgz", - "integrity": "sha512-rKquEGjebqizyHNMOpaE/4FdYR5VQiWFeesqYfvJU0seSEyB4625UGhNOO/qIkH10S3wftiV7oefc8WdLZ/gCQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-sdFVnQJRkQBX83ydsLCBm4A39p45y0QkxdAR689yOtAFNbbS9Acrp86RZWJj6BHRXyZH9tX4t1dU7XDiGdY3nA==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/connect": { - "version": "3.4.36", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz", - "integrity": "sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==", + "version": "3.4.37", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz", + "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/cors": { - "version": "2.8.14", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.14.tgz", - "integrity": "sha512-RXHUvNWYICtbP6s18PnOCaqToK8y14DnLd75c6HfyKf228dxy7pHNOQkxPtvXKp/hINFMDjbYzsj63nnpPMSRQ==", + "version": "2.8.15", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", + "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/express": { - "version": "4.17.18", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.18.tgz", - "integrity": "sha512-Sxv8BSLLgsBYmcnGdGjjEjqET2U+AKAdCRODmMiq02FgjwuV75Ut85DRpvFjyw/Mk0vgUOliGRU0UUmuuZHByQ==", + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", + "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -659,9 +651,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.37", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.37.tgz", - "integrity": "sha512-ZohaCYTgGFcOP7u6aJOhY9uIZQgZ2vxC2yWoArY+FeDXlqeH66ZVBjgvg+RLVAS/DWNq4Ap9ZXu1+SUQiiWYMg==", + "version": "4.17.38", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.38.tgz", + "integrity": "sha512-hXOtc0tuDHZPFwwhuBJXPbjemWtXnJjbvuuyNH2Y5Z6in+iXc63c4eXYDc7GGGqHy+iwYqAJMdaItqdnbcBKmg==", "dev": true, "dependencies": { "@types/node": "*", @@ -671,78 +663,81 @@ } }, "node_modules/@types/http-errors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.2.tgz", - "integrity": "sha512-lPG6KlZs88gef6aD85z3HNkztpj7w2R7HmR3gygjfXCQmsLloWNARFkMuzKiiY8FGdh1XDpgBdrSf4aKDiA7Kg==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz", + "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==", "dev": true }, "node_modules/@types/jsonwebtoken": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", - "integrity": "sha512-b0jGiOgHtZ2jqdPgPnP6WLCXZk1T8p06A/vPGzUvxpFGgKMbjXJDjC5m52ErqBnIuWZFgGoIJyRdeG5AyreJjA==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.4.tgz", + "integrity": "sha512-8UYapdmR0QlxgvJmyE8lP7guxD0UGVMfknsdtCFZh4ovShdBl3iOI4zdvqBHrB/IS+xUj3PSx73Qkey1fhWz+g==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/mime": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.3.tgz", - "integrity": "sha512-Ys+/St+2VF4+xuY6+kDIXGxbNRO0mesVg0bbxEfB97Od1Vjpjx9KD1qxs64Gcb3CWPirk9Xe+PT4YiiHQ9T+eg==", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz", + "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==", "dev": true }, "node_modules/@types/morgan": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.6.tgz", - "integrity": "sha512-xfKogz5WcKww2DAiVT9zxMgrqQt+Shq8tDVeLT+otoj6dJnkRkyJxMF51mHtUc3JCPKGk5x1EBU0buuGpfftlQ==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.7.tgz", + "integrity": "sha512-4sJFBUBrIZkP5EvMm1L6VCXp3SQe8dnXqlVpe1jsmTjS1JQVmSjnpMNs8DosQd6omBi/K7BSKJ6z/Mc3ki0K9g==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/multer": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.8.tgz", - "integrity": "sha512-VMZOW6mnmMMhA5m3fsCdXBwFwC+a+27/8gctNMuQC4f7UtWcF79KAFGoIfKZ4iqrElgWIa3j5vhMJDp0iikQ1g==", + "version": "1.4.9", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-1.4.9.tgz", + "integrity": "sha512-9NSvPJ2E8bNTc8XtJq1Cimx2Wrn2Ah48F15B2Du/hM8a8CHLhVbJMlF3ZCqhvMdht7Sa+YdP0aKP7N4fxDcrrg==", "dev": true, "dependencies": { "@types/express": "*" } }, "node_modules/@types/node": { - "version": "20.8.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", - "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==", - "dev": true + "version": "20.8.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", + "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/parse-link-header": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/parse-link-header/-/parse-link-header-2.0.1.tgz", - "integrity": "sha512-BrKNSrRTqn3UkMXvdVtr/znJch0PMBpEvEP8oBkxDx7eEGntuFLI+WpA5HGsNHK4SlqyhaMa+Ks0ViwyixQB5w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-link-header/-/parse-link-header-2.0.2.tgz", + "integrity": "sha512-RKU5SIF0oyM2ZI0ubw66FkM/0RJUv/r84I7vJcXkcICcfeOpd1WXfpcqkFJPaWli5z3YdxMsfWojyU5uofT6sA==", "dev": true }, "node_modules/@types/qs": { - "version": "6.9.8", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz", - "integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg==", + "version": "6.9.9", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", + "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==", "dev": true }, "node_modules/@types/range-parser": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz", - "integrity": "sha512-xrO9OoVPqFuYyR/loIHjnbvvyRZREYKLjxV4+dY6v3FQR3stQ9ZxIGkaclF7YhI9hfjpuTbu14hZEy94qKLtOA==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", + "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", "dev": true }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", "dev": true }, "node_modules/@types/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.2.tgz", - "integrity": "sha512-aAG6yRf6r0wQ29bkS+x97BIs64ZLxeE/ARwyS6wrldMm3C1MdKwCcnnEwMC1slI8wuxJOpiUH9MioC0A0i+GJw==", + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz", + "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==", "dev": true, "dependencies": { "@types/mime": "^1", @@ -750,9 +745,9 @@ } }, "node_modules/@types/serve-static": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.3.tgz", - "integrity": "sha512-yVRvFsEMrv7s0lGhzrggJjNOSmZCdgCjw9xWrPr/kNNLp6FaDfMC1KaYl3TSJ0c58bECwNBMoQrZJ8hA8E1eFg==", + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", + "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", "dev": true, "dependencies": { "@types/http-errors": "*", @@ -770,14 +765,14 @@ } }, "node_modules/@types/triple-beam": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.3.tgz", - "integrity": "sha512-6tOUG+nVHn0cJbVp25JFayS5UE6+xlbcNF9Lo9mU7U0zk3zeUShZied4YEQZjy1JBF043FSkdXw8YkUJuVtB5g==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.4.tgz", + "integrity": "sha512-HlJjF3wxV4R2VQkFpKe0YqJLilYNgtRtsqqZtby7RkVsSs+i+vbyzjtUwpFEdUCKcrGzCiEJE7F/0mKjh0sunA==" }, "node_modules/@types/uuid": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.4.tgz", - "integrity": "sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA==", + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.6.tgz", + "integrity": "sha512-BT2Krtx4xaO6iwzwMFUYvWBWkV2pr37zD68Vmp1CDV196MzczBRxuEpD6Pr395HAgebC/co7hOphs53r8V7jew==", "dev": true }, "node_modules/abbrev": { @@ -1006,11 +1001,6 @@ "node": ">= 0.8" } }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" - }, "node_modules/bignumber.js": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", @@ -2117,9 +2107,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/genversion": { "version": "3.1.1", @@ -2875,16 +2868,19 @@ } }, "node_modules/logform": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", - "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", "fecha": "^4.2.0", "ms": "^2.1.1", "safe-stable-stringify": "^2.3.1", "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" } }, "node_modules/logform/node_modules/ms": { @@ -3128,9 +3124,9 @@ } }, "node_modules/node": { - "version": "20.7.0", - "resolved": "https://registry.npmjs.org/node/-/node-20.7.0.tgz", - "integrity": "sha512-GiKqtgSALW8+W7Zi9T2AI9aME8hJg+1EESH6O7Xmk4k1gJfBKOolpy9gdg8vCyR8dMeJlp5GQZOYnvxsu8v5TA==", + "version": "20.8.1", + "resolved": "https://registry.npmjs.org/node/-/node-20.8.1.tgz", + "integrity": "sha512-gG+nhijBgjTNjgPB4BxKaBKnFS49bngOuxw1/jVh4vlscg/6K+00n+2Q4LEnklTZJXFUQM+AqyGdfvh9h1JknA==", "hasInstallScript": true, "dependencies": { "node-bin-setup": "^1.0.0" @@ -3236,9 +3232,9 @@ } }, "node_modules/npm": { - "version": "9.8.1", - "resolved": "https://registry.npmjs.org/npm/-/npm-9.8.1.tgz", - "integrity": "sha512-AfDvThQzsIXhYgk9zhbk5R+lh811lKkLAeQMMhSypf1BM7zUafeIIBzMzespeuVEJ0+LvY36oRQYf7IKLzU3rw==", + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-9.9.0.tgz", + "integrity": "sha512-wkd7sjz4KmdmddYQcd0aTP73P1cEuPlekeulz4jTDeMVx/Zo5XZ5KQ1z3eUzV3Q/WZpEO0NJXTrD5FNFe6fhCA==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -3283,6 +3279,7 @@ "ms", "node-gyp", "nopt", + "normalize-package-data", "npm-audit-report", "npm-install-checks", "npm-package-arg", @@ -3299,6 +3296,7 @@ "read", "semver", "sigstore", + "spdx-expression-parse", "ssri", "supports-color", "tar", @@ -3312,8 +3310,8 @@ "dev": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^6.3.0", - "@npmcli/config": "^6.2.1", + "@npmcli/arborist": "^6.5.0", + "@npmcli/config": "^6.4.0", "@npmcli/fs": "^3.1.0", "@npmcli/map-workspaces": "^3.0.4", "@npmcli/package-json": "^4.0.1", @@ -3337,12 +3335,12 @@ "is-cidr": "^4.0.2", "json-parse-even-better-errors": "^3.0.0", "libnpmaccess": "^7.0.2", - "libnpmdiff": "^5.0.19", - "libnpmexec": "^6.0.3", - "libnpmfund": "^4.0.19", + "libnpmdiff": "^5.0.20", + "libnpmexec": "^6.0.4", + "libnpmfund": "^4.2.1", "libnpmhook": "^9.0.3", "libnpmorg": "^5.0.4", - "libnpmpack": "^5.0.19", + "libnpmpack": "^5.0.20", "libnpmpublish": "^7.5.0", "libnpmsearch": "^6.0.2", "libnpmteam": "^5.0.3", @@ -3354,10 +3352,11 @@ "ms": "^2.1.2", "node-gyp": "^9.4.0", "nopt": "^7.2.0", + "normalize-package-data": "^5.0.0", "npm-audit-report": "^5.0.0", - "npm-install-checks": "^6.1.1", + "npm-install-checks": "^6.2.0", "npm-package-arg": "^10.1.0", - "npm-pick-manifest": "^8.0.1", + "npm-pick-manifest": "^8.0.2", "npm-profile": "^7.0.1", "npm-registry-fetch": "^14.0.5", "npm-user-validate": "^2.0.0", @@ -3369,7 +3368,8 @@ "qrcode-terminal": "^0.12.0", "read": "^2.1.0", "semver": "^7.5.4", - "sigstore": "^1.7.0", + "sigstore": "^1.9.0", + "spdx-expression-parse": "^3.0.1", "ssri": "^10.0.4", "supports-color": "^9.4.0", "tar": "^6.1.15", @@ -3472,7 +3472,7 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "6.3.0", + "version": "6.5.0", "dev": true, "inBundle": true, "license": "ISC", @@ -3495,7 +3495,7 @@ "json-stringify-nice": "^1.1.4", "minimatch": "^9.0.0", "nopt": "^7.0.0", - "npm-install-checks": "^6.0.0", + "npm-install-checks": "^6.2.0", "npm-package-arg": "^10.1.0", "npm-pick-manifest": "^8.0.1", "npm-registry-fetch": "^14.0.3", @@ -3519,7 +3519,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "6.2.1", + "version": "6.4.0", "dev": true, "inBundle": true, "license": "ISC", @@ -3712,22 +3712,48 @@ "node": ">=14" } }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.1.0", + "version": "0.2.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "1.0.0", "dev": true, "inBundle": true, "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "make-fetch-happen": "^11.0.1" + }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "1.0.2", + "version": "1.0.3", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/protobuf-specs": "^0.2.0", "tuf-js": "^1.1.7" }, "engines": { @@ -4716,12 +4742,12 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "5.0.19", + "version": "5.0.20", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.3.0", + "@npmcli/arborist": "^6.5.0", "@npmcli/disparity-colors": "^3.0.0", "@npmcli/installed-package-contents": "^2.0.2", "binary-extensions": "^2.2.0", @@ -4736,12 +4762,12 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "6.0.3", + "version": "6.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.3.0", + "@npmcli/arborist": "^6.5.0", "@npmcli/run-script": "^6.0.0", "ci-info": "^3.7.1", "npm-package-arg": "^10.1.0", @@ -4758,12 +4784,12 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "4.0.19", + "version": "4.2.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.3.0" + "@npmcli/arborist": "^6.5.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -4796,12 +4822,12 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "5.0.19", + "version": "5.0.20", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^6.3.0", + "@npmcli/arborist": "^6.5.0", "@npmcli/run-script": "^6.0.0", "npm-package-arg": "^10.1.0", "pacote": "^15.0.8" @@ -5347,7 +5373,7 @@ } }, "node_modules/npm/node_modules/npm-install-checks": { - "version": "6.1.1", + "version": "6.2.0", "dev": true, "inBundle": true, "license": "BSD-2-Clause", @@ -5395,7 +5421,7 @@ } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "8.0.1", + "version": "8.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -5889,13 +5915,15 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "1.7.0", + "version": "1.9.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.1.0", - "@sigstore/tuf": "^1.0.1", + "@sigstore/bundle": "^1.1.0", + "@sigstore/protobuf-specs": "^0.2.0", + "@sigstore/sign": "^1.0.0", + "@sigstore/tuf": "^1.0.3", "make-fetch-happen": "^11.0.1" }, "bin": { @@ -6360,9 +6388,9 @@ } }, "node_modules/object-inspect": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", - "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz", + "integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6562,13 +6590,13 @@ } }, "node_modules/prisma": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.3.1.tgz", - "integrity": "sha512-Wp2msQIlMPHe+5k5Od6xnsI/WNG7UJGgFUJgqv/ygc7kOECZapcSz/iU4NIEzISs3H1W9sFLjAPbg/gOqqtB7A==", + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.4.2.tgz", + "integrity": "sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg==", "devOptional": true, "hasInstallScript": true, "dependencies": { - "@prisma/engines": "5.3.1" + "@prisma/engines": "5.4.2" }, "bin": { "prisma": "build/index.js" @@ -6747,9 +6775,9 @@ } }, "node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7376,6 +7404,12 @@ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", "dev": true }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -7485,11 +7519,11 @@ } }, "node_modules/winston": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.10.0.tgz", - "integrity": "sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", "dependencies": { - "@colors/colors": "1.5.0", + "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", "async": "^3.2.3", "is-stream": "^2.0.0", @@ -7506,16 +7540,16 @@ } }, "node_modules/winston-transport": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", - "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", "triple-beam": "^1.3.0" }, "engines": { - "node": ">= 6.4.0" + "node": ">= 12.0.0" } }, "node_modules/winston-transport/node_modules/readable-stream": { diff --git a/ExpressAPI/package.json b/ExpressAPI/package.json index c251fe54ccd93983fb524e22c7c20c6ff99e0388..ea2f9c786f6ce4702db6f53ed8b9031f116f203b 100644 --- a/ExpressAPI/package.json +++ b/ExpressAPI/package.json @@ -1,7 +1,7 @@ { "name" : "dojo_backend_api", "description" : "Backend API of the Dojo project", - "version" : "2.2.0", + "version" : "3.0.0", "license" : "AGPLv3", "author" : "Michaël Minelli <dojo@minelli.me>", "main" : "dist/src/app.js", @@ -24,7 +24,6 @@ "@prisma/client" : "^5.1.1", "ajv" : "^8.12.0", "axios" : "^1.4.0", - "bcryptjs" : "^2.4.3", "compression" : "^1.7.4", "cors" : "^2.8.5", "dotenv" : "^16.3.1", @@ -48,7 +47,6 @@ "winston" : "^3.8.2" }, "devDependencies": { - "@types/bcryptjs" : "^2.4.2", "@types/compression" : "^1.7.2", "@types/cors" : "^2.8.13", "@types/express" : "^4.17.17", diff --git a/ExpressAPI/prisma/migrations/20231019130319_user_login_gitlab_migration/migration.sql b/ExpressAPI/prisma/migrations/20231019130319_user_login_gitlab_migration/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..55d6884fff7db5497d31d0d2b9c2c5c4a8b087f2 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20231019130319_user_login_gitlab_migration/migration.sql @@ -0,0 +1,20 @@ +/* + Warnings: + + - You are about to drop the column `firstname` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `lastname` on the `User` table. All the data in the column will be lost. + - You are about to drop the column `password` on the `User` table. All the data in the column will be lost. + - A unique constraint covering the columns `[gitlabUsername]` on the table `User` will be added. If there are existing duplicate values, this will fail. + - Added the required column `gitlabUsername` to the `User` table without a default value. This is not possible if the table is not empty. + +*/ +-- AlterTable +ALTER TABLE `User` DROP COLUMN `firstname`, + DROP COLUMN `lastname`, + DROP COLUMN `password`, + ADD COLUMN `gitlabLastInfo` JSON NOT NULL, + ADD COLUMN `gitlabUsername` VARCHAR(191) NOT NULL, + ADD COLUMN `name` VARCHAR(191) NULL; + +-- CreateIndex +CREATE UNIQUE INDEX `User_gitlabUsername_key` ON `User`(`gitlabUsername`); diff --git a/ExpressAPI/prisma/migrations/20231019131336_add_user_roles/migration.sql b/ExpressAPI/prisma/migrations/20231019131336_add_user_roles/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..bb6981f18bd28efc0ed6e750544a3fc594205bd4 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20231019131336_add_user_roles/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to alter the column `role` on the `User` table. The data in that column could be lost. The data in that column will be cast from `VarChar(191)` to `Enum(EnumId(0))`. + +*/ +-- AlterTable +ALTER TABLE `User` MODIFY `role` ENUM('STUDENT', 'TEACHING_STAFF', 'ADMIN') NULL DEFAULT 'STUDENT'; diff --git a/ExpressAPI/prisma/migrations/20231019133101_user_move_gitlab_id_to_user_id/migration.sql b/ExpressAPI/prisma/migrations/20231019133101_user_move_gitlab_id_to_user_id/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..384000e267b9d1d4973b90b8d7a2d2f197748910 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20231019133101_user_move_gitlab_id_to_user_id/migration.sql @@ -0,0 +1,12 @@ +/* + Warnings: + + - You are about to drop the column `gitlabId` on the `User` table. All the data in the column will be lost. + +*/ +-- DropIndex +DROP INDEX `User_gitlabId_key` ON `User`; + +-- AlterTable +ALTER TABLE `User` DROP COLUMN `gitlabId`, + MODIFY `id` INTEGER NOT NULL; diff --git a/ExpressAPI/prisma/migrations/20231019141626_user_store_refresh_token/migration.sql b/ExpressAPI/prisma/migrations/20231019141626_user_store_refresh_token/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..86d1c29b4175daca6a1c5bcf506987a61154a955 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20231019141626_user_store_refresh_token/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE `User` ADD COLUMN `gitlabLastRefreshToken` VARCHAR(191) NULL; diff --git a/ExpressAPI/prisma/migrations/20231020204832_user_remove_refresh_token/migration.sql b/ExpressAPI/prisma/migrations/20231020204832_user_remove_refresh_token/migration.sql new file mode 100644 index 0000000000000000000000000000000000000000..46fda322d4927352cf931a964ead45bba72d2045 --- /dev/null +++ b/ExpressAPI/prisma/migrations/20231020204832_user_remove_refresh_token/migration.sql @@ -0,0 +1,8 @@ +/* + Warnings: + + - You are about to drop the column `gitlabLastRefreshToken` on the `User` table. All the data in the column will be lost. + +*/ +-- AlterTable +ALTER TABLE `User` DROP COLUMN `gitlabLastRefreshToken`; diff --git a/ExpressAPI/prisma/schema.prisma b/ExpressAPI/prisma/schema.prisma index df6640eb8f98e4e2c1802ac29ac7c194f3800b28..a68226e0868e475d54557f330fa35699e2f34bf7 100644 --- a/ExpressAPI/prisma/schema.prisma +++ b/ExpressAPI/prisma/schema.prisma @@ -7,15 +7,20 @@ datasource db { url = env("DATABASE_URL") } +enum UserRole { + STUDENT + TEACHING_STAFF + ADMIN +} + model User { - id Int @id @default(autoincrement()) - firstname String - lastname String? - mail String? @unique - password String? - gitlabId Int @unique - role String? - deleted Boolean @default(false) + id Int @id /// The user's id is the same as their gitlab id + name String? + mail String? @unique + role UserRole? @default(STUDENT) + gitlabUsername String @unique + gitlabLastInfo Json @default("{}") @db.Json + deleted Boolean @default(false) assignments Assignment[] exercises Exercise[] diff --git a/ExpressAPI/prisma/seed.ts b/ExpressAPI/prisma/seed.ts index 603712461e4588d80a27b4b282f32922ae0e230b..ec4b605c97444027c3ce74f6cde381da9b6d7f1e 100644 --- a/ExpressAPI/prisma/seed.ts +++ b/ExpressAPI/prisma/seed.ts @@ -1,25 +1,20 @@ -require('dotenv').config(); // ATTENTION : This line MUST be the first of this file -require('../src/shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be the second of this file +require('../src/InitialImports'); // ATTENTION : These lines MUST be the first of this file -import Config from '../src/config/Config'; -import logger from '../src/shared/logging/WinstonLogger'; -import * as bcrypt from 'bcryptjs'; -import db from '../src/helpers/DatabaseHelper'; +import { UserRole } from '@prisma/client'; +import logger from '../src/shared/logging/WinstonLogger'; +import db from '../src/helpers/DatabaseHelper'; async function main() { await db.user.upsert({ - where : { gitlabId: 142 }, + where : { id: 142 }, update: {}, create: { - id : 1, - firstname: 'Michaël', - lastname : 'Minelli', - mail : 'michael@minelli.me', - password : bcrypt.hashSync('123456', Config.userPasswordSaltRounds), - gitlabId : 142, - role : 'colsci', - deleted : false + id : 142, + gitlabUsername: 'michael.minelli', + gitlabLastInfo: {}, + role : UserRole.ADMIN, + deleted : false } }); } diff --git a/ExpressAPI/src/InitialImports.ts b/ExpressAPI/src/InitialImports.ts new file mode 100644 index 0000000000000000000000000000000000000000..1ba7814dd1acfaf666c7878f6fb0446b82b7b4c4 --- /dev/null +++ b/ExpressAPI/src/InitialImports.ts @@ -0,0 +1,13 @@ +import path from 'node:path'; + + +if ( process.env.NODE_ENV && process.env.NODE_ENV === 'production' ) { + const myEnv = require('dotenv').config(); + require('dotenv-expand').expand(myEnv); +} else { + require('dotenv').config({ path: path.join(__dirname, '../.env.keys') }); + const myEnv = require('dotenv').config({ DOTENV_KEY: process.env.DOTENV_KEY_DEVELOPMENT }); + require('dotenv-expand').expand(myEnv); +} + +require('./shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be after the dotenv.config() calls diff --git a/ExpressAPI/src/app.ts b/ExpressAPI/src/app.ts index bfbc0494636c237af8dae3185fc2670eb0c51b67..9317f3869137d6789fd35a2dc18fb7c313d48f2b 100644 --- a/ExpressAPI/src/app.ts +++ b/ExpressAPI/src/app.ts @@ -1,17 +1,4 @@ -// Read from the .env file -// ATTENTION : This lines MUST be the first of this file (except for the path import) -const path = require('node:path'); - -if ( process.env.NODE_ENV && process.env.NODE_ENV === 'production' ) { - const myEnv = require('dotenv').config(); - require('dotenv-expand').expand(myEnv); -} else { - require('dotenv').config({ path: path.join(__dirname, '../.env.keys') }); - const myEnv = require('dotenv').config({ DOTENV_KEY: process.env.DOTENV_KEY_DEVELOPMENT }); - require('dotenv-expand').expand(myEnv); -} - -require('./shared/helpers/TypeScriptExtensions'); // ATTENTION : This line MUST be after the dotenv.config() calls +require('./InitialImports'); // ATTENTION : These lines MUST be the first of this file import WorkerRole from './process/WorkerRole'; import ClusterManager from './process/ClusterManager'; diff --git a/ExpressAPI/src/config/Config.ts b/ExpressAPI/src/config/Config.ts index 574f9b2ea0e987c896a5075d4ac6dac7f7dbac55..beab7cc8a1cc89ed8e148766c2e1207d62a1ec8d 100644 --- a/ExpressAPI/src/config/Config.ts +++ b/ExpressAPI/src/config/Config.ts @@ -5,7 +5,9 @@ import { Exercise } from '../types/DatabaseTypes'; import JSON5 from 'json5'; -type ConfigGitlabBadge = { link: string, imageUrl: string } +type ConfigGitlabBadge = { + link: string, imageUrl: string +} class Config { @@ -13,31 +15,48 @@ class Config { port: number }; - public readonly requestClientValidation: { version: { [client: string]: string } }; // { version: { CLIENT: CONDITION } } + public readonly requestClientValidation: { + version: { + [client: string]: string + } + }; // { version: { CLIENT: CONDITION } } public readonly jwtConfig: { secret: string; expiresIn: number; }; - public readonly permissions: { - teachingStaff: Array<string>; + public readonly login: { + gitlab: { + client: { + secret: string + } + } }; public readonly gitlab: { - urls: Array<string>; account: { id: number; username: string; token: string; }; group: { root: number; templates: number; assignments: number; exercises: number; }, badges: { pipeline: ConfigGitlabBadge } + urls: Array<string>; repository: { + timeoutAfterCreation: number; + }; account: { + id: number; username: string; token: string; + }; group: { + root: number; templates: number; assignments: number; exercises: number; + }, badges: { + pipeline: ConfigGitlabBadge + } }; public readonly assignment: { - default: { description: string; initReadme: boolean; sharedRunnersEnabled: boolean; visibility: string; wikiEnabled: boolean; template: string }; baseFiles: Array<string>; filename: string + default: { + description: string; initReadme: boolean; sharedRunnersEnabled: boolean; visibility: string; wikiEnabled: boolean; template: string + }; baseFiles: Array<string>; filename: string }; public readonly exercise: { - maxSameName: number; resultsFolder: string, pipelineResultsFolder: string; default: { description: string; visibility: string; }; + maxSameName: number; resultsFolder: string, pipelineResultsFolder: string; default: { + description: string; visibility: string; + }; }; - public readonly userPasswordLength: number; - public readonly userPasswordSaltRounds: number; - constructor() { this.api = { port: Number(process.env.API_PORT || 30992) @@ -46,60 +65,43 @@ class Config { this.requestClientValidation = JSON5.parse(process.env.REQUEST_CLIENT_VALIDATION || '{"version": {}}'); this.jwtConfig = { - secret : process.env.JWT_SECRET_KEY || '', - expiresIn: Number(process.env.SESSION_TIMEOUT || 0) + secret: process.env.JWT_SECRET_KEY || '', expiresIn: Number(process.env.SESSION_TIMEOUT || 0) }; - this.permissions = { - teachingStaff: JSON5.parse(process.env.ROLES_WITH_TEACHING_STAFF_PERMISSIONS || '[]') + this.login = { + gitlab: { + client: { + secret: process.env.LOGIN_GITLAB_CLIENT_SECRET || '' + } + } }; this.gitlab = { - urls : JSON5.parse(process.env.GITLAB_URLS || '[]'), - account: { - id : Number(process.env.GITLAB_DOJO_ACCOUNT_ID || 0), - username: process.env.GITLAB_DOJO_ACCOUNT_USERNAME || '', - token : process.env.GITLAB_DOJO_ACCOUNT_TOKEN || '' - }, - group : { - root : Number(process.env.GITLAB_GROUP_ROOT_ID || 0), - templates : Number(process.env.GITLAB_GROUP_TEMPLATES_ID || 0), - assignments: Number(process.env.GITLAB_GROUP_ASSIGNMENTS_ID || 0), - exercises : Number(process.env.GITLAB_GROUP_EXERCISES_ID || 0) - }, - badges : { + urls : JSON5.parse(process.env.GITLAB_URLS || '[]'), account: { + id: Number(process.env.GITLAB_DOJO_ACCOUNT_ID || 0), username: process.env.GITLAB_DOJO_ACCOUNT_USERNAME || '', token: process.env.GITLAB_DOJO_ACCOUNT_TOKEN || '' + }, repository: { + timeoutAfterCreation: Number(process.env.GITLAB_REPOSITORY_CREATION_TIMEOUT || 5000) + }, group : { + root: Number(process.env.GITLAB_GROUP_ROOT_ID || 0), templates: Number(process.env.GITLAB_GROUP_TEMPLATES_ID || 0), assignments: Number(process.env.GITLAB_GROUP_ASSIGNMENTS_ID || 0), exercises: Number(process.env.GITLAB_GROUP_EXERCISES_ID || 0) + }, badges : { pipeline: { - link : process.env.GITLAB_BADGE_PIPELINE_LINK || '', - imageUrl: process.env.GITLAB_BADGE_PIPELINE_IMAGE_URL || '' + link: process.env.GITLAB_BADGE_PIPELINE_LINK || '', imageUrl: process.env.GITLAB_BADGE_PIPELINE_IMAGE_URL || '' } } }; this.assignment = { - default : { - description : process.env.ASSIGNMENT_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '', - initReadme : process.env.ASSIGNMENT_DEFAULT_INIT_README?.toBoolean() ?? false, - sharedRunnersEnabled: process.env.ASSIGNMENT_DEFAULT_SHARED_RUNNERS_ENABLED?.toBoolean() ?? true, - visibility : process.env.ASSIGNMENT_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE, - wikiEnabled : process.env.ASSIGNMENT_DEFAULT_WIKI_ENABLED?.toBoolean() ?? false, - template : process.env.ASSIGNMENT_DEFAULT_TEMPLATE?.replace('{{USERNAME}}', this.gitlab.account.username).replace('{{TOKEN}}', this.gitlab.account.token) ?? '' - }, - baseFiles: JSON5.parse(process.env.ASSIGNMENT_BASE_FILES || '[]'), - filename : process.env.ASSIGNMENT_FILENAME || '' + default : { + description: process.env.ASSIGNMENT_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '', initReadme: process.env.ASSIGNMENT_DEFAULT_INIT_README?.toBoolean() ?? false, sharedRunnersEnabled: process.env.ASSIGNMENT_DEFAULT_SHARED_RUNNERS_ENABLED?.toBoolean() ?? true, visibility: process.env.ASSIGNMENT_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE, wikiEnabled: process.env.ASSIGNMENT_DEFAULT_WIKI_ENABLED?.toBoolean() ?? false, template: process.env.ASSIGNMENT_DEFAULT_TEMPLATE?.replace('{{USERNAME}}', this.gitlab.account.username).replace('{{TOKEN}}', this.gitlab.account.token) ?? '' + }, baseFiles: JSON5.parse(process.env.ASSIGNMENT_BASE_FILES || '[]'), filename: process.env.ASSIGNMENT_FILENAME || '' }; this.exercise = { - maxSameName : Number(process.env.EXERCISE_MAX_SAME_NAME || 0), - resultsFolder : process.env.EXERCISE_RESULTS_FOLDER?.convertWithEnvVars() ?? '', - pipelineResultsFolder: process.env.EXERCISE_PIPELINE_RESULTS_FOLDER ?? '', //Do not use convertWithEnvVars() because it is used in the exercise creation and muste be interpreted at exercise runtime - default : { - description: process.env.EXERCISE_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '', - visibility : process.env.EXERCISE_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE + maxSameName: Number(process.env.EXERCISE_MAX_SAME_NAME || 0), resultsFolder: process.env.EXERCISE_RESULTS_FOLDER?.convertWithEnvVars() ?? '', pipelineResultsFolder: process.env.EXERCISE_PIPELINE_RESULTS_FOLDER ?? '', //Do not use convertWithEnvVars() because it is used in the exercise creation and muste be interpreted at exercise runtime + default : { + description: process.env.EXERCISE_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '', visibility: process.env.EXERCISE_DEFAULT_VISIBILITY || GitlabVisibility.PRIVATE } }; - - this.userPasswordLength = Number(process.env.USER_PASSWORD_LENGTH || 0); - this.userPasswordSaltRounds = Number(process.env.USER_PASSWORD_SALT_ROUNDS || 10); } public getResultsFolder(exercise: Exercise): string { diff --git a/ExpressAPI/src/controllers/Session.ts b/ExpressAPI/src/controllers/Session.ts index 77549d8630df98d91b1d4b1e5ef5a7851f91621e..49e044eab67d18a2108e54ef54c1d4e59b6896bb 100644 --- a/ExpressAPI/src/controllers/Session.ts +++ b/ExpressAPI/src/controllers/Session.ts @@ -16,7 +16,6 @@ class Session { } set profile(newProfile: User) { - delete newProfile.password; this._profile = newProfile; } diff --git a/ExpressAPI/src/helpers/GlobalHelper.ts b/ExpressAPI/src/helpers/GlobalHelper.ts new file mode 100644 index 0000000000000000000000000000000000000000..c97328d8e5cbc2d99b7339da2a94219e4ef01618 --- /dev/null +++ b/ExpressAPI/src/helpers/GlobalHelper.ts @@ -0,0 +1,33 @@ +import express from 'express'; +import GitlabRepository from '../shared/types/Gitlab/GitlabRepository'; +import logger from '../shared/logging/WinstonLogger'; +import GitlabManager from '../managers/GitlabManager'; +import { AxiosError } from 'axios'; +import { StatusCodes } from 'http-status-codes'; +import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; + + +class GlobalHelper { + async repositoryCreationError(message: string, error: any, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: GitlabRepository): Promise<void> { + logger.error(message); + logger.error(error); + + try { + if ( repositoryToRemove ) { + await GitlabManager.deleteRepository(repositoryToRemove.id); + } + } catch ( error ) { + logger.error('Repository deletion error'); + logger.error(error); + } + + if ( error instanceof AxiosError ) { + return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown gitlab error: ${ message }`, gitlabError); + } + + return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ message }`, internalError); + }; +} + + +export default new GlobalHelper(); \ No newline at end of file diff --git a/ExpressAPI/src/helpers/Prisma/Extensions/UserResultExtension.ts b/ExpressAPI/src/helpers/Prisma/Extensions/UserResultExtension.ts index 9315569e912f7acb2ef0084bf926e90c0d56d9a0..9ece43dcc31b2dd9fde697a33948f6d72fc15247 100644 --- a/ExpressAPI/src/helpers/Prisma/Extensions/UserResultExtension.ts +++ b/ExpressAPI/src/helpers/Prisma/Extensions/UserResultExtension.ts @@ -1,8 +1,7 @@ -import { Prisma } from '@prisma/client'; -import Config from '../../../config/Config'; -import LazyVal from '../../../shared/helpers/LazyVal'; -import GitlabUser from '../../../shared/types/Gitlab/GitlabUser'; -import GitlabManager from '../../../managers/GitlabManager'; +import { Prisma, UserRole } from '@prisma/client'; +import LazyVal from '../../../shared/helpers/LazyVal'; +import GitlabUser from '../../../shared/types/Gitlab/GitlabUser'; +import GitlabManager from '../../../managers/GitlabManager'; export default Prisma.defineExtension(client => { @@ -14,16 +13,21 @@ export default Prisma.defineExtension(client => { role: true }, compute(user) { - return Config.permissions.teachingStaff.includes(user.role!); + return user.role == UserRole.TEACHING_STAFF || user.role == UserRole.ADMIN; } }, - gitlabProfile : { + isAdmin : { needs: { - gitlabId: true + role: true }, + compute(user) { + return user.role == UserRole.ADMIN; + } + }, + gitlabProfile : { compute(user) { return new LazyVal<GitlabUser | undefined>(() => { - return GitlabManager.getUserById(user.gitlabId); + return GitlabManager.getUserById(user.id); }); } } diff --git a/ExpressAPI/src/managers/GitlabManager.ts b/ExpressAPI/src/managers/GitlabManager.ts index fca3977ce07f14eada038511f9106ccf539fba0a..0c93da87efa87ca244f7a11d21d831ccb7c1bc16 100644 --- a/ExpressAPI/src/managers/GitlabManager.ts +++ b/ExpressAPI/src/managers/GitlabManager.ts @@ -12,6 +12,7 @@ import GitlabFile from '../shared/types/Gitlab/GitlabFile'; import express from 'express'; import GitlabRoute from '../shared/types/Gitlab/GitlabRoute'; import SharedConfig from '../shared/config/SharedConfig'; +import GitlabProfile from '../shared/types/Gitlab/GitlabProfile'; class GitlabManager { @@ -19,6 +20,20 @@ class GitlabManager { return `${ SharedConfig.gitlab.apiURL }${ route }`; } + public async getUserProfile(token: string): Promise<GitlabProfile | undefined> { + try { + return (await axios.get<GitlabProfile>(this.getApiUrl(GitlabRoute.PROFILE_GET), { + headers: { + DojoOverrideAuthorization: true, + DojoAuthorizationHeader : 'Authorization', + DojoAuthorizationValue : `Bearer ${ token }` + } + })).data; + } catch ( e ) { } + + return undefined; + } + public async getUserById(id: number): Promise<GitlabUser | undefined> { try { const params: any = {}; @@ -69,6 +84,10 @@ class GitlabManager { return response.data; } + async deleteRepository(repoId: number): Promise<void> { + return await axios.delete(this.getApiUrl(GitlabRoute.REPOSITORY_DELETE).replace('{{id}}', String(repoId))); + } + async forkRepository(forkId: number, name: string, path: string, description: string, visibility: string, namespace: number): Promise<GitlabRepository> { const response = await axios.post<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_FORK).replace('{{id}}', String(forkId)), { name : name, @@ -142,7 +161,7 @@ class GitlabManager { }; members.forEach(member => { if ( member.access_level >= GitlabAccessLevel.REPORTER ) { - if ( member.id === req.session.profile.gitlabId ) { + if ( member.id === req.session.profile.id ) { isUsersAtLeastReporter.user = true; } else if ( member.id === Config.gitlab.account.id ) { isUsersAtLeastReporter.dojo = true; @@ -203,8 +222,10 @@ class GitlabManager { return response.data; } - async createFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) { - await axios.post(this.getApiUrl(GitlabRoute.REPOSITORY_FILE).replace('{{id}}', String(repoId)).replace('{{filePath}}', encodeURIComponent(filePath)), { + private async createUpdateFile(create: boolean, repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) { + const axiosFunction = create ? axios.post : axios.put; + + await axiosFunction(this.getApiUrl(GitlabRoute.REPOSITORY_FILE).replace('{{id}}', String(repoId)).replace('{{filePath}}', encodeURIComponent(filePath)), { encoding : 'base64', branch : branch, commit_message: commitMessage, @@ -213,6 +234,14 @@ class GitlabManager { author_email : authorMail }); } + + async createFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) { + return this.createUpdateFile(true, repoId, filePath, fileBase64, commitMessage, branch, authorName, authorMail); + } + + async updateFile(repoId: number, filePath: string, fileBase64: string, commitMessage: string, branch: string = 'main', authorName: string = 'Dojo', authorMail: string | undefined = undefined) { + return this.createUpdateFile(false, repoId, filePath, fileBase64, commitMessage, branch, authorName, authorMail); + } } diff --git a/ExpressAPI/src/managers/HttpManager.ts b/ExpressAPI/src/managers/HttpManager.ts index 6d04c68f0b0536bfa9bead9a6e78978bf5946c9b..075e72717a56923fe0d962b72ac14d11fad0d9e8 100644 --- a/ExpressAPI/src/managers/HttpManager.ts +++ b/ExpressAPI/src/managers/HttpManager.ts @@ -18,7 +18,17 @@ class HttpManager { } if ( config.url && config.url.indexOf(SharedConfig.gitlab.apiURL) !== -1 ) { - config.headers['PRIVATE-TOKEN'] = Config.gitlab.account.token; + if ( !config.headers.DojoOverrideAuthorization ) { + config.headers['PRIVATE-TOKEN'] = Config.gitlab.account.token; + } + } + + if ( config.headers.DojoOverrideAuthorization && 'DojoAuthorizationHeader' in config.headers && 'DojoAuthorizationValue' in config.headers ) { + config.headers[config.headers.DojoAuthorizationHeader] = config.headers.DojoAuthorizationValue; + + delete config.headers.DojoOverrideAuthorization; + delete config.headers.DojoAuthorizationHeader; + delete config.headers.DojoAuthorizationValue; } return config; diff --git a/ExpressAPI/src/managers/UserManager.ts b/ExpressAPI/src/managers/UserManager.ts index 615cbcb37cb5c5b6ec06731c50a1acd391260956..b69705e1e6b5c65c29efe2a0590b27b7a51c48b2 100644 --- a/ExpressAPI/src/managers/UserManager.ts +++ b/ExpressAPI/src/managers/UserManager.ts @@ -1,7 +1,8 @@ -import GitlabUser from '../shared/types/Gitlab/GitlabUser'; -import { Prisma } from '@prisma/client'; -import db from '../helpers/DatabaseHelper'; -import { User } from '../types/DatabaseTypes'; +import GitlabUser from '../shared/types/Gitlab/GitlabUser'; +import { Prisma } from '@prisma/client'; +import db from '../helpers/DatabaseHelper'; +import GitlabProfile from '../shared/types/Gitlab/GitlabProfile'; +import { User } from '../types/DatabaseTypes'; class UserManager { @@ -23,23 +24,36 @@ class UserManager { }) as unknown as User ?? undefined; } - async getByGitlabId(gitlabId: number, returnIdIfUndefined: boolean = true, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> { - return await db.user.findUnique({ - where : { - gitlabId: gitlabId - }, - include: include - }) as unknown as User ?? (returnIdIfUndefined ? gitlabId : undefined); + async getUpdateFromGitlabProfile(gitlabProfile: GitlabProfile, refreshToken: string): Promise<User> { + await db.user.upsert({ + where : { + id: gitlabProfile.id + }, + update: { + mail : gitlabProfile.email, + gitlabLastInfo: gitlabProfile + }, + create: { + id : gitlabProfile.id, + name : gitlabProfile.name, + mail : gitlabProfile.email, + gitlabUsername: gitlabProfile.username, + gitlabLastInfo: gitlabProfile, + deleted : false + } + }); + + return (await this.getById(gitlabProfile.id))!; } async getFromGitlabUser(gitlabUser: GitlabUser, createIfNotExist: boolean = false, include: Prisma.UserInclude | undefined = undefined): Promise<User | number | undefined> { - let user = await this.getByGitlabId(gitlabUser.id, true, include); + let user = await this.getById(gitlabUser.id, include) ?? gitlabUser.id; if ( typeof user === 'number' && createIfNotExist ) { user = (await db.user.create({ data: { - firstname: gitlabUser.name, - gitlabId : gitlabUser.id + id : gitlabUser.id, + gitlabUsername: gitlabUser.name } })).id; } diff --git a/ExpressAPI/src/routes/AssignmentRoutes.ts b/ExpressAPI/src/routes/AssignmentRoutes.ts index 0e8926263d792b77a20c60ca36b1c64134a5f3d5..e4eb82bfa416c6fcfb1062b84883551c9b821988 100644 --- a/ExpressAPI/src/routes/AssignmentRoutes.ts +++ b/ExpressAPI/src/routes/AssignmentRoutes.ts @@ -23,6 +23,8 @@ import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibil import fs from 'fs'; import path from 'path'; import SharedAssignmentHelper from '../shared/helpers/Dojo/SharedAssignmentHelper'; +import GlobalHelper from '../helpers/GlobalHelper'; +import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; class AssignmentRoutes implements RoutesManager { @@ -86,11 +88,10 @@ class AssignmentRoutes implements RoutesManager { let repository: GitlabRepository; try { repository = await GitlabManager.createRepository(params.name, Config.assignment.default.description.replace('{{ASSIGNMENT_NAME}}', params.name), Config.assignment.default.visibility, Config.assignment.default.initReadme, Config.gitlab.group.assignments, Config.assignment.default.sharedRunnersEnabled, Config.assignment.default.wikiEnabled, params.template); - - await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER); - - await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'); } catch ( error ) { + logger.error('Repo creation error'); + logger.error(error); + if ( error instanceof AxiosError ) { if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) { return res.status(StatusCodes.CONFLICT).send(); @@ -99,27 +100,32 @@ class AssignmentRoutes implements RoutesManager { return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); } - logger.error(error); return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); } + await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation)); + try { - await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/assignment_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); - } catch ( error ) { - logger.error(error); + await GitlabManager.protectBranch(repository.id, '*', true, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER); - if ( error instanceof AxiosError ) { - return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); - } + await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'); + } catch ( error ) { + return GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository); + } - return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); + try { + await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/assignment_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); + } catch ( error ) { + return GlobalHelper.repositoryCreationError('CI file error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository); } try { await Promise.all(params.members.map(member => member.id).map(async (memberId: number): Promise<GitlabMember | false> => { try { return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER); - } catch ( e ) { + } catch ( error ) { + logger.error('Add member error'); + logger.error(error); return false; } })); @@ -136,11 +142,11 @@ class AssignmentRoutes implements RoutesManager { connectOrCreate: [ ...params.members.map(gitlabUser => { return { create: { - gitlabId : gitlabUser.id, - firstname: gitlabUser.name + id : gitlabUser.id, + gitlabUsername: gitlabUser.name }, where : { - gitlabId: gitlabUser.id + id: gitlabUser.id } }; }) ] @@ -150,12 +156,7 @@ class AssignmentRoutes implements RoutesManager { return req.session.sendResponse(res, StatusCodes.OK, assignment); } catch ( error ) { - if ( error instanceof AxiosError ) { - return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); - } - - logger.error(error); - return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); + return GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.ASSIGNMENT_CREATION_GITLAB_ERROR, DojoStatusCode.ASSIGNMENT_CREATION_INTERNAL_ERROR, repository); } } diff --git a/ExpressAPI/src/routes/ExerciseRoutes.ts b/ExpressAPI/src/routes/ExerciseRoutes.ts index e773d8c2f08c1484a830a28edb962e4031d9de73..8bc2e8a43832d6d59e8fb253d6d857fad24de290 100644 --- a/ExpressAPI/src/routes/ExerciseRoutes.ts +++ b/ExpressAPI/src/routes/ExerciseRoutes.ts @@ -1,32 +1,34 @@ -import { Express } from 'express-serve-static-core'; -import express from 'express'; -import * as ExpressValidator from 'express-validator'; -import { StatusCodes } from 'http-status-codes'; -import RoutesManager from '../express/RoutesManager'; -import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware'; -import SecurityMiddleware from '../middlewares/SecurityMiddleware'; -import GitlabUser from '../shared/types/Gitlab/GitlabUser'; -import GitlabManager from '../managers/GitlabManager'; -import Config from '../config/Config'; -import GitlabRepository from '../shared/types/Gitlab/GitlabRepository'; -import { AxiosError, HttpStatusCode } from 'axios'; -import logger from '../shared/logging/WinstonLogger'; -import DojoValidators from '../helpers/DojoValidators'; -import { v4 as uuidv4 } from 'uuid'; -import GitlabMember from '../shared/types/Gitlab/GitlabMember'; -import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel'; -import { Prisma } from '@prisma/client'; -import { Assignment, Exercise } from '../types/DatabaseTypes'; -import db from '../helpers/DatabaseHelper'; -import SecurityCheckType from '../types/SecurityCheckType'; -import GitlabTreeFile from '../shared/types/Gitlab/GitlabTreeFile'; -import GitlabFile from '../shared/types/Gitlab/GitlabFile'; -import GitlabTreeFileType from '../shared/types/Gitlab/GitlabTreeFileType'; -import JSON5 from 'json5'; -import fs from 'fs'; -import path from 'path'; -import AssignmentFile from '../shared/types/Dojo/AssignmentFile'; -import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile'; +import { Express } from 'express-serve-static-core'; +import express from 'express'; +import * as ExpressValidator from 'express-validator'; +import { StatusCodes } from 'http-status-codes'; +import RoutesManager from '../express/RoutesManager'; +import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware'; +import SecurityMiddleware from '../middlewares/SecurityMiddleware'; +import GitlabUser from '../shared/types/Gitlab/GitlabUser'; +import GitlabManager from '../managers/GitlabManager'; +import Config from '../config/Config'; +import GitlabRepository from '../shared/types/Gitlab/GitlabRepository'; +import { AxiosError } from 'axios'; +import logger from '../shared/logging/WinstonLogger'; +import DojoValidators from '../helpers/DojoValidators'; +import { v4 as uuidv4 } from 'uuid'; +import GitlabMember from '../shared/types/Gitlab/GitlabMember'; +import GitlabAccessLevel from '../shared/types/Gitlab/GitlabAccessLevel'; +import { Prisma } from '@prisma/client'; +import { Assignment, Exercise } from '../types/DatabaseTypes'; +import db from '../helpers/DatabaseHelper'; +import SecurityCheckType from '../types/SecurityCheckType'; +import GitlabTreeFile from '../shared/types/Gitlab/GitlabTreeFile'; +import GitlabFile from '../shared/types/Gitlab/GitlabFile'; +import GitlabTreeFileType from '../shared/types/Gitlab/GitlabTreeFileType'; +import JSON5 from 'json5'; +import fs from 'fs'; +import path from 'path'; +import AssignmentFile from '../shared/types/Dojo/AssignmentFile'; +import ExerciseResultsFile from '../shared/types/Dojo/ExerciseResultsFile'; +import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; +import GlobalHelper from '../helpers/GlobalHelper'; class ExerciseRoutes implements RoutesManager { @@ -95,50 +97,55 @@ class ExerciseRoutes implements RoutesManager { do { try { repository = await GitlabManager.forkRepository((assignment.gitlabCreationInfo as unknown as GitlabRepository).id, this.getExerciseName(assignment, params.members, suffix), this.getExercisePath(req.boundParams.assignment!, exerciseId), Config.exercise.default.description.replace('{{ASSIGNMENT_NAME}}', assignment.name), Config.exercise.default.visibility, Config.gitlab.group.exercises); - - await GitlabManager.protectBranch(repository.id, '*', false, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER); - - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true); - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true); - await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false); - - await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'); - break; } catch ( error ) { + logger.error('Repo creation error'); + logger.error(error); + if ( error instanceof AxiosError ) { if ( error.response?.data.message.name && error.response.data.message.name == 'has already been taken' ) { suffix++; } else { - return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); + return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown gitlab error while forking repository', DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR); } } else { - return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); + return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown error while forking repository', DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR); } } } while ( suffix < Config.exercise.maxSameName ); if ( suffix >= Config.exercise.maxSameName ) { + logger.error('Max exercise with same name reached'); return res.status(StatusCodes.INSUFFICIENT_SPACE_ON_RESOURCE).send(); } + await new Promise(resolve => setTimeout(resolve, Config.gitlab.repository.timeoutAfterCreation)); + try { - await GitlabManager.createFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); - } catch ( error ) { - logger.error(error); + await GitlabManager.protectBranch(repository.id, '*', false, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.DEVELOPER, GitlabAccessLevel.OWNER); - if ( error instanceof AxiosError ) { - return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); - } + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_EXERCISE_ID', exerciseId, false, true); + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_SECRET', secret, false, true); + await GitlabManager.addRepositoryVariable(repository.id, 'DOJO_RESULTS_FOLDER', Config.exercise.pipelineResultsFolder, false, false); - return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); + await GitlabManager.addRepositoryBadge(repository.id, Config.gitlab.badges.pipeline.link, Config.gitlab.badges.pipeline.imageUrl, 'Pipeline Status'); + } catch ( error ) { + return GlobalHelper.repositoryCreationError('Repo params error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); + } + + try { + await GitlabManager.updateFile(repository.id, '.gitlab-ci.yml', fs.readFileSync(path.join(__dirname, '../../assets/exercise_gitlab_ci.yml'), 'base64'), 'Add .gitlab-ci.yml (DO NOT MODIFY THIS FILE)'); + } catch ( error ) { + return GlobalHelper.repositoryCreationError('CI file update error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); } try { - await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.gitlabId), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => { + await Promise.all([ ...new Set([ ...assignment.staff.map(user => user.id), ...params.members.map(member => member.id) ]) ].map(async (memberId: number): Promise<GitlabMember | false> => { try { return await GitlabManager.addRepositoryMember(repository.id, memberId, GitlabAccessLevel.DEVELOPER); - } catch ( e ) { + } catch ( error ) { + logger.error('Add member error'); + logger.error(error); return false; } })); @@ -158,11 +165,11 @@ class ExerciseRoutes implements RoutesManager { connectOrCreate: [ ...params.members.map(gitlabUser => { return { create: { - gitlabId : gitlabUser.id, - firstname: gitlabUser.name + id : gitlabUser.id, + gitlabUsername: gitlabUser.name }, where : { - gitlabId: gitlabUser.id + id: gitlabUser.id } }; }) ] @@ -172,13 +179,7 @@ class ExerciseRoutes implements RoutesManager { return req.session.sendResponse(res, StatusCodes.OK, exercise); } catch ( error ) { - logger.error(error); - - if ( error instanceof AxiosError ) { - return res.status(error.response?.status ?? HttpStatusCode.InternalServerError).send(); - } - - return res.status(StatusCodes.INTERNAL_SERVER_ERROR).send(); + return GlobalHelper.repositoryCreationError('DB error', error, req, res, DojoStatusCode.EXERCISE_CREATION_GITLAB_ERROR, DojoStatusCode.EXERCISE_CREATION_INTERNAL_ERROR, repository); } } diff --git a/ExpressAPI/src/routes/SessionRoutes.ts b/ExpressAPI/src/routes/SessionRoutes.ts index eb329d88b7ccfe6f026a755a7f213bee0ddf1cb7..0479205b47fa69630d954e3c6e08aa703f716043 100644 --- a/ExpressAPI/src/routes/SessionRoutes.ts +++ b/ExpressAPI/src/routes/SessionRoutes.ts @@ -2,21 +2,30 @@ import { Express } from 'express-serve-static-core'; import express from 'express'; import * as ExpressValidator from 'express-validator'; import { StatusCodes } from 'http-status-codes'; -import * as bcrypt from 'bcryptjs'; import RoutesManager from '../express/RoutesManager'; import ParamsValidatorMiddleware from '../middlewares/ParamsValidatorMiddleware'; -import UserManager from '../managers/UserManager'; import SecurityMiddleware from '../middlewares/SecurityMiddleware'; -import { User } from '../types/DatabaseTypes'; +import GitlabManager from '../managers/GitlabManager'; +import UserManager from '../managers/UserManager'; +import DojoStatusCode from '../shared/types/Dojo/DojoStatusCode'; +import SharedGitlabManager from '../shared/managers/SharedGitlabManager'; +import Config from '../config/Config'; class SessionRoutes implements RoutesManager { private readonly loginValidator: ExpressValidator.Schema = { - user : { + accessToken : { trim : true, notEmpty: true }, - password: { + refreshToken: { + trim : true, + notEmpty: true + } + }; + + private readonly refreshTokensValidator: ExpressValidator.Schema = { + refreshToken: { trim : true, notEmpty: true } @@ -24,26 +33,43 @@ class SessionRoutes implements RoutesManager { registerOnBackend(backend: Express) { backend.post('/login', ParamsValidatorMiddleware.validate(this.loginValidator), this.login); + backend.post('/refresh_tokens', ParamsValidatorMiddleware.validate(this.refreshTokensValidator), this.refreshTokens); backend.get('/test_session', SecurityMiddleware.check(true), (req: express.Request, res: express.Response) => req.session.sendResponse(res, StatusCodes.OK)); } private async login(req: express.Request, res: express.Response) { - const params: { - user: string, password: string - } = req.body; + try { + const params: { + accessToken: string, refreshToken: string + } = req.body; - const user: User | undefined = await UserManager.getByMail(params.user); + const gitlabUser = await GitlabManager.getUserProfile(params.accessToken); - if ( user ) { - if ( bcrypt.compareSync(params.password, user.password ?? '') ) { - req.session.profile = user; + if ( gitlabUser ) { + req.session.profile = await UserManager.getUpdateFromGitlabProfile(gitlabUser, params.refreshToken); req.session.sendResponse(res, StatusCodes.OK); return; + } else { + req.session.sendResponse(res, StatusCodes.NOT_FOUND); } + } catch ( error ) { + req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown error while logging in', DojoStatusCode.LOGIN_FAILED); } + } + + private async refreshTokens(req: express.Request, res: express.Response) { + try { + const params: { + refreshToken: string + } = req.body; - req.session.sendResponse(res, StatusCodes.NOT_FOUND); + const gitlabTokens = await SharedGitlabManager.getTokens(params.refreshToken, true, Config.login.gitlab.client.secret); + + req.session.sendResponse(res, StatusCodes.OK, gitlabTokens); + } catch ( error ) { + req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, 'Unknown error while refresh tokens', DojoStatusCode.REFRESH_TOKENS_FAILED); + } } } diff --git a/ExpressAPI/src/shared b/ExpressAPI/src/shared index efe1bf313f57d1826faf935c183d37a0835f8c2d..4a5eb68209ae9204b6d4cc8020bd62cf6a5be989 160000 --- a/ExpressAPI/src/shared +++ b/ExpressAPI/src/shared @@ -1 +1 @@ -Subproject commit efe1bf313f57d1826faf935c183d37a0835f8c2d +Subproject commit 4a5eb68209ae9204b6d4cc8020bd62cf6a5be989 diff --git a/ExpressAPI/src/types/DatabaseTypes.ts b/ExpressAPI/src/types/DatabaseTypes.ts index bdb25f8c14088d4dcc8524f309a52d5380556a1c..632b05be5eda9eebf30a8c392e5a4020292dd10d 100644 --- a/ExpressAPI/src/types/DatabaseTypes.ts +++ b/ExpressAPI/src/types/DatabaseTypes.ts @@ -26,9 +26,9 @@ const resultBase = Prisma.validator<Prisma.ResultDefaultArgs>()({ }); -export type User = Omit<Prisma.UserGetPayload<typeof userBase>, 'password'> & { - password?: string +export type User = Prisma.UserGetPayload<typeof userBase> & { isTeachingStaff: boolean + isAdmin: boolean gitlabProfile: LazyVal<GitlabUser> } export type Assignment = Prisma.AssignmentGetPayload<typeof assignmentBase>