Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • add_route_assignments
  • ask-user-to-delete-exercises-on-duplicates
  • bedran_exercise-list
  • jw_sonar
  • jw_sonar_backup
  • main
  • update-dependencies
  • v6.0.0
  • 2.0.0
  • 2.1.0
  • 2.2.0
  • 3.0.0
  • 3.0.1
  • 3.1.0
  • 3.1.1
  • 3.1.2
  • 3.1.3
  • 3.2.0
  • 3.3.0
  • 3.4.0
  • 3.4.1
  • 3.4.2
  • 3.5.0
  • 3.5.1
  • 3.5.2
  • 3.5.3
  • 4.0.0
  • 4.1.0
  • 5.0.0
  • 5.0.1
  • 6.0.0-dev
  • v1.0.1
32 results

Target

Select target project
  • Dojo_Project_Nguyen/backend/dojobackendapi
  • dojo_project/projects/backend/dojobackendapi
2 results
Select Git revision
  • add_route_assignments
  • ask-user-to-delete-exercises-on-duplicates
  • bedran_exercise-list
  • jw_sonar
  • jw_sonar_backup
  • main
  • update-dependencies
  • v6.0.0
  • 2.0.0
  • 2.1.0
  • 2.2.0
  • 3.0.0
  • 3.0.1
  • 3.1.0
  • 3.1.1
  • 3.1.2
  • 3.1.3
  • 3.2.0
  • 3.3.0
  • 3.4.0
  • 3.4.1
  • 3.4.2
  • 3.5.0
  • 3.5.1
  • 3.5.2
  • 3.5.3
  • 4.0.0
  • 4.1.0
  • 5.0.0
  • 5.0.1
  • 6.0.0-dev
  • v1.0.1
32 results
Show changes
Commits on Source (22)
Showing
with 4289 additions and 1364 deletions
......@@ -4,6 +4,9 @@ workspace.xml
Wiki/.idea
ExpressAPI/src/config/Version.ts
redoc.html
OpenAPI.yaml-r
############################ MacOS
# General
......
......@@ -55,12 +55,25 @@ variables:
stages:
- code_quality
- test
- clean
- upload
- release
code_quality:lint:
stage: code_quality
tags:
- code_quality
image: node:latest
script:
- cd "${PROJECT_FOLDER}"
- npm install
- npm run lint
test:build:
stage: test
image: node:latest
......
......@@ -17,7 +17,17 @@
- No modifications / Keep major and minors versions in sync with all parts of the project
-->
## 3.0.0 (?)
## 3.1.0 (???)
### 🔨 Internal / Developers
- **Typescript**: Add linter (ESLint)
### 📚 Documentation
- **API**: Routes documentation with Swagger
## 3.0.0 (2023-11-03)
### ✨ Feature
- Login to Dojo app via Gitlab OAuth
......
......@@ -4,8 +4,11 @@
#/--------------------------------------------------/
# 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="//eidHk8xbcNgl8Bcuu47JqNewiU+CwFGRPJo+Xq71Y/P4TlP9cpEIRH8FPVtZDmC7UnUgvSDjpteDZ+YvndOdLuOt7HiM0cbP1IJiGhS5FyFcJUUqjmV1vGrYwof5X9tKsEe9AsW9q0oUS0eXVPzxmn+AKo6Q8/dGqp/QAnBIsqFUHZZSK9THeJybTZCx0jduBZEwcVqwJMtuEMna0ScBNgUnQ+Oc3cC1xNvdi2k8rhDooVUJK5cLUEnzC6pWCi3Dwr0MJuRKoOXYTx0kvdq8OpR/aowjBmfE0eC2qXlmi1Haeqt0H/A/RF25rdQ0z6nFfmsj7yasxW/Lx3ysNIwsQ4SMBQb0/DhBqtew6KydhUlk4QzwGApQ9maH0JaN1zWUHySbM54qib+BZHqtOOgMXJDuATRpRT6GT4SYM3FfhbZAs9DFYzOiNIOjDFZxVOJbqbLJsnZ2SX7TarDdMW9IOg7bNasYrSmrx+ChLlIOMlxPBqfod4K0fOa7IqqCBqpRaZYv9rKisTgIDEAlkLsgrdlzOYl4rVsb9RyeHoa1IT8ud5V1swKIOhxyIofA742kvGccgK8y/GtpcqwBkEYEZ2/pf56pH3VuC1LBZujgGXQLM3/OmR56YcboFoK3pw3NazqAAdkcgGgX6UAkcKJJBzlX+piUu/wjxRagiI54PLX5RBgi164KI0dM0ucq7Ep9PwJybrk+BJiZOPtNcZprSXlVpS6jomwBYqX02ywdHjzVnBZLby18LsWoM9TOlXwNij14uwewJBwAtAnpjXtCev5nXT1U1orJP5JWQe8THmzQQgeUr1K2IgrWEcAxyZWI5mKQjktqNyuPwh3zrGAkS4vQi0VWqQ/+SH+glXyj6JekLAAQfoVB6P47/VMVXRr6qccv069B/B9jTA3XB0g0zNMnkcd7iM1FQUm6C7QEG/gjcb0C4ZVfB+PfR+vnAdfPDCv86LREa9GcD7A2pTrz2cLaKIyLobRus5e+d/SgdK83n4XNoWuXB1Vt1Epq1DgD3zzqke6gIKHn0OcvwHVu2FZj8TIH2Zg9Nu719eyvm1Jd0HQBKZrTIzXKxuF/RlW7pNHaXJOWXFgE2XEYKieLBX6kvCjUtRj8+H/kYJkMuYTa/oMqhEGZojkuNw5wtzKfLrPIr7e9kIc9UQzsUlxsGw23XqdcpBxvfrDpXcxLJyz3ydVJIR5EOdgRpnTh330cw2eZRamORxjnZLvpQtqa8o9AQ/7cU4MK1hxLEB4luey80NGWco8fwDXChWoWvf1YfkgiL6w0hwgxu+lA4ILOzIYgYFsAprKeAoxabtpHIavhVk17CiRcC75jZMonW5eiIEuu+6vmQwNbnu8OeM8MHuxYuzLwKmldzhqHCUDlS2Qkv6ABVLL1kaIgkQZhyWxo2GnmEbB9lAMgfbm+KjDwh/WG7ApYcfg8+sbAoD6RbXmgCOdDloX3DewjxfWy2W8gRUQOUOG3WewbpYLoVyA/NOSiUi8tz1D3aSWQhQYsZqkvp8iPAbH1lSAB0+eme14bFXd3rOP87AvxoQJHuP7mZ0ySn/bRZT7J6wkT6VN7Iid2cMalm8wJsfXZo6Dg5azSIdbZgXDcnHSfIanQTw2cts1/OrGjqkBC/BfMhcc4QS6e4d8gMdKUFFx9TMc4tkllHvuJM4ZCPRrVQZIB2XjhBcQ5Nbz+ZpjSEZnb3zc724uBN7mBEvy9ByIJc8y3uSvDtkbmukX6jz9VgFxc2qO56nMCXVogyt0ysGBoWbg9mBSMr3sN5EaEB28yxfL/uQA5Kt4k8Ul8HY7cgkf5BUYudBUBO+2qMY29xlj2auundHTqrSpyFzsHTYKHYYcHvwYKE/N5UKC+SgPRC8cmfsZUylTv0WY+OIj2rJO1xJVAA8cJfsSAMLECRLusEdvp/Q5CfbJwEEsfpLT7FqzTJEEsANN3VfFeZ6bTDWeH9GlwSJcIrhzr4LjTTwtVqNXz/APbl6lV4lMiwNdLTxdTl11SFv2Nw2F4iSPgwZdoZuWmv4gID4SQZSPP1eKYbB823heDgLx5LA4bwW9YKLyBP9AACtew0eqQLYGvYQcMbDs38nfAKd3F5C+B4OLpTxZoAgMGAU7ZYnva8Oe58YmfR1a5rdwTLpaRj1KGIF15k+9+CA7MWb6J8VtA4krCjSQqoJZH0KxF9NJR4qez9bZ3wEeCORblaxM7E1nwdNfA55/j3RZcw3I9xhZTGCeUT1ZQz/50Tz9UCLHsNuv4cdKk5n4NRNOPK1yq7LCOmFewZJFAIZJxwHs8IzGc/JmqxTjmuIDUnhlJ2riTA5r5EkQ5mVmhFaI/c4ePoDokG514EJ04R5oUweW+I5IXyC094MDB0SohtgsMH8eOBmmYxRRlcXja+hGmg11SfIKFMvwxOM+U89h5NtzJEIVCNpwOOeKcdareNujClGioNCfwKR+77MOrbsRKb35fJNCUAeaFQAfVMzKWMRn+xtyjtI7uCohymA5lSSn1oBLR5Babl/EzW7chejuwhxV/fqG4KlcFyAgDBDxjpXhIgm680rFTX/dqOaUzHgsUPt2wuBNtqQdvtR7OKfiqzQjG2Ht3l4rtGZvOa5jVfV974grrxGnRtujl9Lso49svQYZYDGPBkouw7jt6L8jFBOXRvY6vfTnfRHtVee+AQ9/khFiiYI/6dUO4qjJQyN0KsF/Y+gpxHWeYvae2FMM9h6cgYSXSM84AkLXacAonIHAewfz5SrN4I/trE9rXEoT1nXvO9Q8DBL9IO9dUFET9vGhn7oYYT3QoKQfxHUMwKy2i7pnORh1pUQCM9aDbIZN+44zGkOzddpy6d4Wck3wSJ1wpXUhJ2jmH0l+ZgxQXy3jrKxYdP4ce8+HpeSC37wldpkrfT26mGTQzUSwYIvdwqIQd3qbZl4aqgWxmuRKKfERZ55FziMDh5pCPnO4BJC94kow2hbtduGUhykOzXHmOoePd1BOVPrM6hbjRLQHsbbGnA2mJyoap+CXsZmFswfJYjfy4SItt1MFdYC8Qcl2GmBK6yF+cnF5G8SvVeG1t+BiS5BI3dz2YX/JZwJFImMus0b+WSqln5XjzGIDlwniCarwApc+22Yv6ZVvcbkmIkBxxrd3rxIOF6aZH0qJ7A8dD5jcSyLV/1Kt0mgG0M5gSOR4OVH8iNbux2eOc8LtlueUarxLXPIsfuxYXwP+ynT5UMEuTb6Zlv1BtlX4EDDcefhBeCveiJ7cNIPoAWMl/jxq36LbkRHDBa6nKk8TvEDTMuvpeg4KXabI8FJUXWs1FVb0BRSlaQnD/f2IxKzYyqsMHdgoxn/QudrYBsp0nyARguI27+XRll5I3QDcWS2Cuo3w+kXLJ38J15f0hwSARpcpqIhKxv5pppWbU2bYuo2BDusmw34ObjlmrDk4oESYnLE9KFLs1MiNEJJ9AY3sE2AbRNYhmDOFijgV25UeoXWsMqxp65tNCPFYZSEdpF0yWNEX2aLcHcK/GrRGZbvmNp2gkDY1hKV8o8N7+Gog7cOHvuBhNFASYYRY5C/uQ=="
# test
DOTENV_VAULT_TEST="rVF2z29+LGw9TGbiqm9SnQCrtNLLs7ufpz+4r05KP6fcZ6xHMdkWizrPUs1ay8c4IFGKc0E7gVNTpaamE87bXAJdq/rraIIzCl9D9jlXy/RdO8S/YzjIxJzYc7yNSzPed8QzMsoDT+a4OTGB36T8EWST8sVGyBG6K7oIh+OZ1cRka/oDz0Freio1BKGk3P/rX2uLW0TrT9BcH8+lbAr0rrgxgdoqBdrVp2qBnMM4VgEbOZe0SC4x2viW6p4n51RIG+0vAhxc5FK1S55+ZV+4mzRlMUYuv8NmK/+Dc6oDnZoup8Lchbk9ProH4P60vTbuPDUmRSgwyr5BCjJ8wt7WxVgqAgLEKaWVmDkrR9BxWG0tozbeD4Ed/mahpdQMDtciZeK460qdSHQ6MmZEKzR4ELyv864NMZNLM3RI+iZy8S8xycLYlKe82Ts+o8jceJQaN3466y1P5IA8pV6x020DXNfzIsutCyQEZJys9F79tz+xIBdZ2dan0TdvwZSh4TmhG/b60SFDnKUGJ4rc0LiYVqsTsJSrW9VBGhfpo9WOqjZQXabRxDHSSd8SeP9n+hHsOgEirV3pHYgS4Wmf5aTkQVimvnSxvG+/CZDwD3/7K3UzTI26rBP+mtMOoZ+pEquhp58wcekyiOhQth+dshJBag+WdhGMS6W7YCtZvA/xUH5kpZht9pe+AFxicANHD1bQS+vfscBSI7aH7/h4+9e3vRjNgxmVJYlVu6Njo4QppDmfpgN29HIGGpvZABfEqg7FF4Hg89vdcOnwSFNPhiEW99H1ULAYTRzYfPD6t7HP8E1tLS4gGOAPXp2uP5CvqL3o9pyy1yivhmDdgsS86XH7/QDoBRn6z0emkGBEiWo0PBkkgBgheaHQf7VLGZ9L4R8fcjwreF5su7DDgFDOGGqyBciGslYadKszDdFUklqVeK2Hb6UghN5Brx+arFge6N0vAupi7CXb+Qj3US4NsjmQdimW0lfcCLz3x6gk6axtVeIAi1yGJFJwCp34UUFnPL+p9jD5vgnFVMlbDfQIQ7K1EQlvER0aYNY9Oy65dkKPeI4N5c2Nk+KTr5zipwQ4h7wUH6rCW2sM6InWhqMirqpYY0GCYljM82G6z08Q8f+D0mdI0fCwrWKWvyfLfx+BOqPLJTpzR9xAZw3mBwJe8HztnnpnySZ8zMgxlOrxv36K8B/0X6B3kq0mFSlBQAm68lZvmqB+EBAkEMYgGA/9voZ0/AJVxebB7ePhOh7aTz24PqZhEF+CuS/EhkKJdVMYKbeqgXClgT6NhVIYBiez6kimajzrH8hPAIEdoMrE373uw48WEzPtBjK/l+TKNzCwihnCo3+zb7h1pDzMhl6NsaRXCqy/J231YzkfRN1zprsHGUexNhIXL6OY/mbWdo/FdG8BKurYiWTgeJvxU7sV5oCQHgdvr7wbLqmetvmUxn3XuIw/VqqI//R+Mn3GYBfmreGPvuhsNBH59Ua6Elv2XGcwW5QMDQSUeLb7FkrMmKgSBVWlfbfcwrNXY1TDa83tmz/iyT47FQ4OGjwSHAbQ01rRxRUMaw11jnhVl6dGVvT+W54FKXlqAEkzzdDZMem9G0yxvLlZc9+oChZZHECep+P+FkEQx2Ow64bs0/4jHdx2MH3xnbRJP1drGnnDFVzcltE0Ez7q5zMWgdgwzyh/mkWMFs3tv6KrQQsyrAD/1ZeHwnx+ytfhUXXSgG/LTXVW/IRbab1unOwtywito2YqPtLeqBhvkMfXLIWXDPvN76V1FrHcemKuJrtrqE42BlCWxIt6gMhSlS4R2dd3gDR61/PddpUj66roD4DAFKBJPHLfiyWoRc8Nwo5hT4SEOT7HgAqGj0Vx0A6Y8cqdRGn7DG1YPULSjO+LXIbaWfRdWQy/KYQZ/5p5nkznpewymzPE1ssB5MC7aGOGgMcTk5rOCugp4AVPg3vncwH71ugT3MoSVed1f6bIB3DHUZwpXgC0q3wUkqSFUgpTQMpEWMoPQmYa6THaI4jQzM0I1gLZgl+3HKIqUii6mizP33uWWlmk549IFnARb9AHlCDLpNt0+j3FzxmpNbmbgaTM4sGfX9NzwipRJWMN+RveSnkp3WVT+1CnEQuymFtF3UlDqK5opqDMFUi/UUQfgL/erMEZgjpRMuPhxriIBOQj2gzllMbwilSiX2wXvQWd2URMX/W41EF5gZDkb7nvrS7q8w72hrfb4B+R/oYA+j4V+2ZVXBVQC/fLGiGhMCjJ2Wq9rZe1YUz3Q9uCiLcaUjKlFO7vj94kjT+/DPpNHhfynofV04D6AI3NkZrbKIqrCzgrR7Rd3gL5x6aVVEXCV0jjx/OROc1NXmMqdsmuV57bvyw3GPscSwfZoZf0mrfq8Cqb2gWkukbFfl7JDGvWX/fZFqbsfcIA/+vVc4nGSR2k6bu0/fT98WULCDKKsLy4CEMawOmdKYOYoVG5Fr8VHnnlo/9rckKm1iAB1kzVLv5vZblFy6kj9/e/b1ypA7bS+prlvd9Ni/1W2/mACpLphFR9Qeay6xIeBUk3feEeK16v4pjU9KMFaaRhPqfS6waaqMrUbRtthoHDQY/S3AI0ywR/DXgUVXIOLJiBy6eJdtnJJUOLQkGB+VQFnfdj4sB4FvbamYv9XFN97ldKie0/iPkrzm3o0+XX43ENZp8sdgLX/efUgu1RzQ378RyXq3ljQTWZ5FrFfTQ8N0/8BV4GJjaIaNCVUWxTSAOAnvmWxoU8dsX1Ya8TUrlx6TVTbVAWCHTThLJMCM3IYzXYKkgFfCj7i1UtNj6hBUDROQ8hz4QfSmt5Fk+je5Jk4iQtk+M4NEkd2UZOnSVd5GDO5vENAE7vdcXIKSer9zC4gp3mW05AYZWEnxrQ4iqyYvCzmkFHD/w+AYwXMbEY2XL4DWtzZU0F+gEpAI8dzcTEb871Bj40o79Eicol2nYn9u1m+ZtoJKWYLY1NdcYXpPcfBddJUBGj19GKOWvLAsVFCmHgNABkHb6GNkkJ2sYg3eVWM2ltmVpKPLME/rT/d+0WYArWnlSzncqDVke/xb8f646w4ntc+KkGEWiiZE2OkDw9dOOsze8z9Oy8jN4dj7R2pYg5BuMBl8SyYnoeHdyK49qXjgPBr77goF0ns3j2DgErgYU7tJwfSL3PoX9n1MdZwjB2O3izj1sfFeDRmoKxie5trZOAUUjNOhCyVQNQnpuXl4tAAtKxlknxBSWDFHJNW5GPUxCTbVl8BfjmEy98/XwG9b9//yqnP9po/bKMVismdliiONjVFc8vBk2qnO1dK0OGTxoDdBP8gQTO4R2L3ByU6IaVpN7+VHUOXYxJBf+uCClefNtTGa3yB02bGSTjVM5P8KChl1FIWRSkuAfJXe0OfQUClhcXiShRSaqBN1qfy7/r7xKIVZKxvHONWS4uZcS/N6phcPOzRAZb0pNPiM6GQ7yCWKybYf7vyx4JynEOx3b3hh42S/m4XkjO3o0NqeKlCvO/mIcOGiAj+BUyZ0jYy9l/W2GaSMc7VQ7vDKrKmQQF+t67HJ+IeAii/ksJ5CtPRgW0AVc="
dist
node_modules
logs
prisma
\ No newline at end of file
{
"root" : true,
"parser" : "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
]
}
\ No newline at end of file
Subproject commit 4d703a2dd39ec0c2b71bbbbda8900588c4e360bd
Subproject commit ffc5d65f9f0f0e825688177425e526131aa84631
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptLibraryMappings">
<includedPredefinedLibrary name="Node.js Core" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EslintConfiguration">
<option name="fix-on-save" value="true" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SwaggerSettings">
<option name="defaultPreviewType" value="SWAGGER_UI" />
</component>
</project>
\ No newline at end of file
This diff is collapsed.
......@@ -9,5 +9,5 @@
"verbose": true,
"ext" : ".ts,.js",
"ignore" : [],
"exec" : "ts-node --files ./src/app.ts"
"exec" : "npm run lint; npm run build:openapi; ts-node --files ./src/app.ts"
}
This diff is collapsed.
{
"name" : "dojo_backend_api",
"description" : "Backend API of the Dojo project",
"version" : "3.0.1",
"version" : "3.1.0",
"license" : "AGPLv3",
"author" : "Michaël Minelli <dojo@minelli.me>",
"main" : "dist/src/app.js",
"scripts" : {
"clean" : "rm -R dist/*",
"dotenv:build" : "npx dotenv-vault local build",
"lint" : "npx eslint .",
"genversion" : "npx genversion -s -e src/config/Version.ts",
"build" : "npm run genversion; npx prisma generate && npx tsc --project ./ && cp -R assets dist/assets",
"build:openapi" : "sed -i -r \"1,20 s/^\\([ ]*version:\\).*$/\\1 $(jq -r .version package.json)/\" assets/OpenAPI/OpenAPI.yaml; npx @redocly/cli build-docs assets/OpenAPI/OpenAPI.yaml --output=assets/OpenAPI/redoc.html",
"build:project" : "npm run genversion; npx prisma generate && npx tsc --project ./ && cp -R assets dist/assets",
"build" : "npm run build:openapi; npm run build:project",
"database:migrate" : "npx prisma migrate deploy",
"database:seed" : "npm run genversion; npx prisma db seed",
"database:deploy" : "npm run database:migrate && npm run database:seed",
......@@ -21,49 +24,53 @@
"seed": "node dist/prisma/seed"
},
"dependencies" : {
"@prisma/client" : "^5.1.1",
"ajv" : "^8.12.0",
"axios" : "^1.4.0",
"compression" : "^1.7.4",
"cors" : "^2.8.5",
"dotenv" : "^16.3.1",
"dotenv-expand" : "^10.0.0",
"express" : "^4.18.2",
"express-validator": "^7.0.1",
"form-data" : "^4.0.0",
"helmet" : "^7.0.0",
"http-status-codes": "^2.2.0",
"json5" : "^2.2.3",
"jsonwebtoken" : "^9.0.0",
"knex" : "^2.4.2",
"morgan" : "^1.10.0",
"multer" : "^1.4.5-lts.1",
"mysql" : "^2.18.1",
"node" : "^20.5.0",
"parse-link-header": "^2.0.0",
"semver" : "^7.5.4",
"tar-stream" : "^3.1.6",
"uuid" : "^9.0.0",
"winston" : "^3.8.2"
"@prisma/client" : "^5.6.0",
"ajv" : "^8.12.0",
"axios" : "^1.6.2",
"compression" : "^1.7.4",
"cors" : "^2.8.5",
"dotenv" : "^16.3.1",
"dotenv-expand" : "^10.0.0",
"express" : "^4.18.2",
"express-validator" : "^7.0.1",
"form-data" : "^4.0.0",
"helmet" : "^7.1.0",
"http-status-codes" : "^2.3.0",
"json5" : "^2.2.3",
"jsonwebtoken" : "^9.0.2",
"morgan" : "^1.10.0",
"multer" : "^1.4.5-lts.1",
"mysql" : "^2.18.1",
"node" : "^20.10.0",
"parse-link-header" : "^2.0.0",
"semver" : "^7.5.4",
"swagger-ui-express": "^5.0.0",
"tar-stream" : "^3.1.6",
"uuid" : "^9.0.1",
"winston" : "^3.11.0"
},
"devDependencies": {
"@types/compression" : "^1.7.2",
"@types/cors" : "^2.8.13",
"@types/express" : "^4.17.17",
"@types/jsonwebtoken" : "^9.0.2",
"@types/morgan" : "^1.9.4",
"@types/multer" : "^1.4.7",
"@types/node" : "^20.4.7",
"@types/parse-link-header": "^2.0.1",
"@types/semver" : "^7.5.3",
"@types/tar-stream" : "^2.2.2",
"@types/uuid" : "^9.0.2",
"dotenv-vault" : "^1.25.0",
"genversion" : "^3.1.1",
"nodemon" : "^3.0.1",
"prisma" : "^5.1.1",
"ts-node" : "^10.9.1",
"typescript" : "^5.1.6",
"npm" : "^9.8.1"
"@redocly/cli" : "^1.5.0",
"@types/compression" : "^1.7.5",
"@types/cors" : "^2.8.17",
"@types/express" : "^4.17.21",
"@types/jsonwebtoken" : "^9.0.5",
"@types/morgan" : "^1.9.9",
"@types/multer" : "^1.4.11",
"@types/node" : "^20.10.3",
"@types/parse-link-header" : "^2.0.3",
"@types/semver" : "^7.5.6",
"@types/swagger-ui-express" : "^4.1.6",
"@types/tar-stream" : "^3.1.3",
"@types/uuid" : "^9.0.7",
"@typescript-eslint/eslint-plugin": "^6.13.2",
"@typescript-eslint/parser" : "^6.13.2",
"dotenv-vault" : "^1.25.0",
"genversion" : "^3.1.1",
"nodemon" : "^3.0.2",
"npm" : "^10.2.4",
"prisma" : "^5.6.0",
"ts-node" : "^10.9.1",
"typescript" : "^5.3.2"
}
}
import path from 'node:path';
import cluster from 'node:cluster';
import myEnv = require('dotenv');
import dotenvExpand = require('dotenv-expand');
if ( cluster.isPrimary ) {
if ( process.env.NODE_ENV && process.env.NODE_ENV === 'production' ) {
const myEnv = require('dotenv').config();
require('dotenv-expand').expand(myEnv);
dotenvExpand.expand(myEnv.config());
} 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);
myEnv.config({ path: path.join(__dirname, '../.env.keys') });
dotenvExpand.expand(myEnv.config({ DOTENV_KEY: process.env.DOTENV_KEY_DEVELOPMENT }));
}
}
......
......@@ -41,7 +41,7 @@ class Session {
}
}
private static getToken(profileJson: any): string | null {
private static getToken(profileJson: unknown): string | null {
return profileJson === null ? null : jwt.sign({ profile: profileJson }, Config.jwtConfig.secret, Config.jwtConfig.expiresIn > 0 ? { expiresIn: Config.jwtConfig.expiresIn } : {});
}
......@@ -52,7 +52,7 @@ class Session {
try {
reasonPhrase = getReasonPhrase(code);
} catch {}
} catch { /* empty */ }
return {
timestamp : (new Date()).toISOString(),
......@@ -67,8 +67,8 @@ class Session {
Send a response to the client
Information: Data could be a promise or an object. If it's a promise, we wait on the data to be resolved before sending the response
*/
sendResponse(res: express.Response, code: number, data?: any, descriptionOverride?: string, internalCode?: number) {
Promise.resolve(data).then((toReturn: any) => {
sendResponse(res: express.Response, code: number, data?: unknown, descriptionOverride?: string, internalCode?: number) {
Promise.resolve(data).then((toReturn: unknown) => {
this.getResponse(internalCode ?? code, toReturn, descriptionOverride).then(response => {
res.status(code).json(response);
});
......
import { Express } from 'express-serve-static-core';
import cors from 'cors';
import morganMiddleware from '../logging/MorganMiddleware';
import { AddressInfo } from 'net';
import http from 'http';
import helmet from 'helmet';
import express from 'express';
import WorkerTask from '../process/WorkerTask';
import multer from 'multer';
import SessionMiddleware from '../middlewares/SessionMiddleware';
import Config from '../config/Config';
import logger from '../shared/logging/WinstonLogger';
import ParamsCallbackManager from '../middlewares/ParamsCallbackManager';
import ApiRoutesManager from '../routes/ApiRoutesManager';
import compression from 'compression';
import ClientVersionMiddleware from '../middlewares/ClientVersionMiddleware';
import { Express } from 'express-serve-static-core';
import cors from 'cors';
import morganMiddleware from '../logging/MorganMiddleware';
import { AddressInfo } from 'net';
import http from 'http';
import helmet from 'helmet';
import express from 'express';
import WorkerTask from '../process/WorkerTask';
import multer from 'multer';
import SessionMiddleware from '../middlewares/SessionMiddleware';
import Config from '../config/Config';
import logger from '../shared/logging/WinstonLogger';
import ParamsCallbackManager from '../middlewares/ParamsCallbackManager';
import ApiRoutesManager from '../routes/ApiRoutesManager';
import compression from 'compression';
import ClientVersionCheckerMiddleware from '../middlewares/ClientVersionCheckerMiddleware';
import swaggerUi from 'swagger-ui-express';
import path from 'path';
class API implements WorkerTask {
......@@ -23,6 +25,17 @@ class API implements WorkerTask {
constructor() {
this.backend = express();
this.initSwagger();
this.initBaseMiddlewares();
this.backend.use(ClientVersionCheckerMiddleware.register());
ParamsCallbackManager.registerOnBackend(this.backend);
SessionMiddleware.registerOnBackend(this.backend);
ApiRoutesManager.registerOnBackend(this.backend);
}
private initBaseMiddlewares() {
this.backend.use(multer({
limits: { fieldSize: 100 * 1024 * 1024 }
}).none()); //Used for extract params from body with format "form-data", The none is for say that we do not wait a file in params
......@@ -30,14 +43,36 @@ class API implements WorkerTask {
this.backend.use(helmet()); //Help to secure express, https://helmetjs.github.io/
this.backend.use(cors()); //Allow CORS requests
this.backend.use(compression()); //Compress responses
}
this.backend.use(ClientVersionMiddleware.register());
ParamsCallbackManager.register(this.backend);
this.backend.use(SessionMiddleware.register());
private initSwagger() {
const options = {
swaggerOptions: {
url: '/docs/OpenAPI.yaml'
}
};
this.backend.get('/docs/OpenAPI.yaml', (req, res) => res.sendFile(path.resolve(__dirname + '/../../assets/OpenAPI/OpenAPI.yaml')));
this.backend.use('/docs/swagger', swaggerUi.serveFiles(undefined, options), swaggerUi.setup(undefined, options));
this.backend.get('/docs/redoc.html', (req, res) => res.sendFile(path.resolve(__dirname + '/../../assets/OpenAPI/redoc.html')));
ApiRoutesManager.registerOnBackend(this.backend);
this.backend.get('/docs/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html lang="en">
<body>
<ul>
<li><a href="/docs/OpenAPI.yaml">OpenAPI</a></li>
<li>GUI
<ul>
<li><a href="/docs/swagger">Swagger</a></li>
<li><a href="/docs/redoc.html">Redoc</a></li>
</ul>
</li>
</ul>
</body>
</html>
`);
});
}
run() {
......
......@@ -5,13 +5,14 @@ import { BailOptions, ValidationChain } from 'expres
import GitlabManager from '../managers/GitlabManager';
import express from 'express';
import SharedExerciseHelper from '../shared/helpers/Dojo/SharedExerciseHelper';
import logger from '../shared/logging/WinstonLogger';
declare type DojoMeta = Meta & {
req: express.Request
};
declare type DojoCustomValidator = (input: any, meta: DojoMeta) => any;
declare type DojoCustomValidator = (input: unknown, meta: DojoMeta) => unknown;
declare type DojoCustomValidatorSchemaOptions = { errorMessage?: FieldMessageFactory | ErrorMessage, negated?: boolean, bail?: boolean | BailOptions, if?: CustomValidator | ValidationChain, options?: CustomValidator }
......@@ -22,7 +23,7 @@ class DojoValidators {
return arg as unknown as DojoCustomValidatorSchemaOptions;
}
private getParamValue(req: express.Request, path: string): any {
private getParamValue(req: express.Request, path: string): unknown {
return 'body' in req && path in req.body ? req.body[path] : req.query[path];
}
......@@ -30,7 +31,9 @@ class DojoValidators {
options: (value) => {
try {
return value == 'null' || value == 'undefined' || value == '' ? null : value;
} catch ( e ) {
} catch ( error ) {
logger.error(`null sanitizer error: ${ error }`);
return value;
}
}
......@@ -39,7 +42,7 @@ class DojoValidators {
readonly jsonSanitizer = this.toValidatorSchemaOptions({
options: (value) => {
try {
return JSON.parse(value);
return JSON.parse(value as string);
} catch ( e ) {
return value;
}
......@@ -54,7 +57,7 @@ class DojoValidators {
path
}) => {
return new Promise((resolve, reject) => {
const template = this.getParamValue(req, path);
const template = this.getParamValue(req, path) as string;
if ( template ) {
GitlabManager.checkTemplateAccess(template, req).then((templateAccess) => {
templateAccess !== StatusCodes.OK ? reject() : resolve(true);
......@@ -77,9 +80,11 @@ class DojoValidators {
} else {
return Config.assignment.default.template;
}
} catch ( e ) { }
} catch ( error ) {
logger.error(`Template url sanitizer error: ${ error }`);
return value;
return value;
}
}
});
......@@ -91,7 +96,7 @@ class DojoValidators {
path
}) => {
return new Promise((resolve, reject) => {
const results = this.getParamValue(req, path);
const results = this.getParamValue(req, path) as string;
if ( results ) {
SharedExerciseHelper.validateResultFile(results, false).isValid ? resolve(true) : reject();
} else {
......
......@@ -8,7 +8,7 @@ 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> {
async repositoryCreationError(message: string, error: unknown, req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: GitlabRepository): Promise<void> {
logger.error(message);
logger.error(error);
......@@ -26,7 +26,7 @@ class GlobalHelper {
}
return req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ message }`, internalError);
};
}
}
......
......@@ -29,36 +29,35 @@ class GitlabManager {
DojoAuthorizationValue : `Bearer ${ token }`
}
})).data;
} catch ( e ) { }
return undefined;
} catch ( e ) {
return undefined;
}
}
public async getUserById(id: number): Promise<GitlabUser | undefined> {
try {
const params: any = {};
const user = (await axios.get<GitlabUser>(`${ this.getApiUrl(GitlabRoute.USERS_GET) }/${ String(id) }`, { params: params })).data;
const user = (await axios.get<GitlabUser>(`${ this.getApiUrl(GitlabRoute.USERS_GET) }/${ String(id) }`)).data;
return user.id === id ? user : undefined;
} catch ( e ) { }
return undefined;
} catch ( e ) {
return undefined;
}
}
public async getUserByUsername(username: string): Promise<GitlabUser | undefined> {
try {
const params: any = {};
const params: Record<string, string> = {};
params['search'] = username;
const user = (await axios.get<Array<GitlabUser>>(this.getApiUrl(GitlabRoute.USERS_GET), { params: params })).data[0];
return user.username === username ? user : undefined;
} catch ( e ) { }
return undefined;
} catch ( e ) {
return undefined;
}
}
async getRepository(idOrNamespace: string): Promise<GitlabRepository> {
const response = await axios.get<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_GET).replace('{{id}}', encodeURIComponent(idOrNamespace)));
async getRepository(projectIdOrNamespace: string): Promise<GitlabRepository> {
const response = await axios.get<GitlabRepository>(this.getApiUrl(GitlabRoute.REPOSITORY_GET).replace('{{id}}', encodeURIComponent(projectIdOrNamespace)));
return response.data;
}
......@@ -141,10 +140,10 @@ class GitlabManager {
return response.data;
}
async checkTemplateAccess(idOrNamespace: string, req: express.Request): Promise<StatusCodes> {
async checkTemplateAccess(projectIdOrNamespace: string, req: express.Request): Promise<StatusCodes> {
// Get the Gitlab project and check if it have public or internal visibility
try {
const project: GitlabRepository = await this.getRepository(idOrNamespace);
const project: GitlabRepository = await this.getRepository(projectIdOrNamespace);
if ( [ GitlabVisibility.PUBLIC.valueOf(), GitlabVisibility.INTERNAL.valueOf() ].includes(project.visibility) ) {
return StatusCodes.OK;
......@@ -154,7 +153,7 @@ class GitlabManager {
}
// Check if the user and dojo are members (with at least reporter access) of the project
const members = await this.getRepositoryMembers(idOrNamespace);
const members = await this.getRepositoryMembers(projectIdOrNamespace);
const isUsersAtLeastReporter = {
user: false,
dojo: false
......@@ -185,15 +184,15 @@ class GitlabManager {
}
async getRepositoryTree(repoId: number, recursive: boolean = true, branch: string = 'main'): Promise<Array<GitlabTreeFile>> {
let address: string | undefined = this.getApiUrl(GitlabRoute.REPOSITORY_TREE).replace('{{id}}', String(repoId));
let params: any = {
const address: string | undefined = this.getApiUrl(GitlabRoute.REPOSITORY_TREE).replace('{{id}}', String(repoId));
let params: Partial<parseLinkHeader.Link | { recursive: boolean, per_page: number }> | undefined = {
pagination: 'keyset',
recursive : recursive,
per_page : 100,
ref : branch
};
let results: Array<GitlabTreeFile> = [];
const results: Array<GitlabTreeFile> = [];
while ( params !== undefined ) {
const response = await axios.get<Array<GitlabTreeFile>>(address, {
......