diff --git a/CHANGELOG.md b/CHANGELOG.md index e685b34a4e788bb34634a5dd33f4f40217ef9aff..3e17ff30b0b8a260162f2ed9fb69367afd430ea7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,12 @@ --> +## 3.5.0 (???) + +### ✨ Feature +- Link a commit of an exercise as a corrige of an assignment + + ## 3.4.2 (2024-01-23) ### 🐛 Bugfix diff --git a/NodeApp/package-lock.json b/NodeApp/package-lock.json index e65258129e6b3233b33eea6eb42fb84f12d39f5e..f971eb6179b3ab26a8212b4d1feca408ddb586fc 100644 --- a/NodeApp/package-lock.json +++ b/NodeApp/package-lock.json @@ -1,14 +1,15 @@ { "name": "dojo_cli", - "version": "3.4.2", + "version": "3.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dojo_cli", - "version": "3.4.2", + "version": "3.5.0", "license": "AGPLv3", "dependencies": { + "@gitbeaker/rest": "^39.34.3", "appdata-path": "^1.0.0", "axios": "^1.6.5", "boxen": "^5.1.2", @@ -260,6 +261,45 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@gitbeaker/core": { + "version": "39.34.3", + "resolved": "https://registry.npmjs.org/@gitbeaker/core/-/core-39.34.3.tgz", + "integrity": "sha512-/3qBXme2MjO38QU2F/MYGon9a4wHKrgtwNzdHHdjpbYJ2/wOGNgbEWSZcibcFkiWVgAjbPXdYqC5sY8hcwGO1w==", + "dependencies": { + "@gitbeaker/requester-utils": "^39.34.3", + "qs": "^6.11.2", + "xcase": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@gitbeaker/requester-utils": { + "version": "39.34.3", + "resolved": "https://registry.npmjs.org/@gitbeaker/requester-utils/-/requester-utils-39.34.3.tgz", + "integrity": "sha512-nMnTkTo4UixHPwPYsYIjp8UdKrmSw3TjvRESexliAeNNq4/LVeyVUyRqBUa1ZI8MXt1nPPnPX3wh8s7rqlm7uA==", + "dependencies": { + "picomatch-browser": "^2.2.6", + "qs": "^6.11.2", + "rate-limiter-flexible": "^4.0.0", + "xcase": "^2.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@gitbeaker/rest": { + "version": "39.34.3", + "resolved": "https://registry.npmjs.org/@gitbeaker/rest/-/rest-39.34.3.tgz", + "integrity": "sha512-SuceThS6WhJtqNNcKmW8j0yUU7aXA4k5a29OWcd6bn7peQ3MXlIpbfvLLRnmuUaYUuxHLnUzZhAfuxaNf4DVtQ==", + "dependencies": { + "@gitbeaker/core": "^39.34.3", + "@gitbeaker/requester-utils": "^39.34.3" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -335,9 +375,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -359,9 +399,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.21", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz", - "integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -779,6 +819,7 @@ "version": "3.0.8", "resolved": "https://registry.npmjs.org/@oclif/screen/-/screen-3.0.8.tgz", "integrity": "sha512-yx6KAqlt3TAHBduS2fMQtJDL2ufIHnDRArrJEOoTTuizxqmjLT+psGYOHpmMl3gvQpFJ11Hs76guUUktzAF9Bg==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", "dev": true, "engines": { "node": ">=12.0.0" @@ -862,18 +903,18 @@ } }, "node_modules/@types/node": { - "version": "18.19.8", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.8.tgz", - "integrity": "sha512-g1pZtPhsvGVTwmeVoexWZLTQaOvXwoSq//pTL0DHeNzUDrFnir4fgETdhjhIxjVnN+hKOuh98+E1eMLnUXstFg==", + "version": "18.19.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.17.tgz", + "integrity": "sha512-SzyGKgwPzuWp2SHhlpXKzCX0pIOfcI4V2eF37nNBJOhwlegQ83omtVQ1XxZpDE06V/d6AQvfQdPfnw0tRC//Ng==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", + "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", "dev": true }, "node_modules/@types/tar-stream": { @@ -900,16 +941,16 @@ "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.0.tgz", - "integrity": "sha512-DUCUkQNklCQYnrBSSikjVChdc84/vMPDQSgJTHBZ64G9bA9w0Crc0rd2diujKbTdp6w2J47qkeHQLoi0rpLCdg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/type-utils": "6.19.0", - "@typescript-eslint/utils": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -935,15 +976,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.0.tgz", - "integrity": "sha512-1DyBLG5SH7PYCd00QlroiW60YJ4rWMuUGa/JBV0iZuqi4l4IK3twKPq5ZkEebmGqRjXWVgsUzfd3+nZveewgow==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -963,13 +1004,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz", - "integrity": "sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -980,13 +1021,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.0.tgz", - "integrity": "sha512-mcvS6WSWbjiSxKCwBcXtOM5pRkPQ6kcDds/juxcy/727IQr3xMEcwr/YLHW2A2+Fp5ql6khjbKBzOyjuPqGi/w==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.19.0", - "@typescript-eslint/utils": "6.19.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1007,9 +1048,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.0.tgz", - "integrity": "sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1020,13 +1061,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz", - "integrity": "sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/visitor-keys": "6.19.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1048,17 +1089,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.0.tgz", - "integrity": "sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.19.0", - "@typescript-eslint/types": "6.19.0", - "@typescript-eslint/typescript-estree": "6.19.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -1073,12 +1114,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz", - "integrity": "sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.19.0", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1275,9 +1316,9 @@ } }, "node_modules/axios": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", - "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz", + "integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==", "dependencies": { "follow-redirects": "^1.15.4", "form-data": "^4.0.0", @@ -1285,9 +1326,9 @@ } }, "node_modules/b4a": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", - "integrity": "sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==" + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==" }, "node_modules/balanced-match": { "version": "1.0.2", @@ -1295,6 +1336,12 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bare-events": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.0.tgz", + "integrity": "sha512-Yyyqff4PIFfSuthCZqLlPISTWHmnQxoPuAvkmgzsJEmG3CesdIv6Xweayl0JkCZJSB2yYIdJyEz97tpxNhgjbg==", + "optional": true + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1403,6 +1450,24 @@ "node": ">=0.10.0" } }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1725,6 +1790,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -1785,14 +1866,14 @@ } }, "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://dotenvx.com" } }, "node_modules/dotenv-expand": { @@ -1804,16 +1885,16 @@ } }, "node_modules/dotenv-vault": { - "version": "1.25.0", - "resolved": "https://registry.npmjs.org/dotenv-vault/-/dotenv-vault-1.25.0.tgz", - "integrity": "sha512-+3isN+iq0E5VE+pfluBcNYb2qFf/Zu5q44Neh3Bazl82vk86xdUbI2z2cYHgJq5bMgRW1kUOaGWsgXjYlGUhng==", + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/dotenv-vault/-/dotenv-vault-1.26.0.tgz", + "integrity": "sha512-2PNnlprtOdFEG9+hAAZxXegcjlJVZMSy88arnRR4YjwU/PwkDbdtk1uzw/D88D5EZ0b84n7YVQ6RccRXmW/Qzg==", "dev": true, "dependencies": { "@oclif/core": "^1", - "@oclif/plugin-help": "^5.2.11", - "@oclif/plugin-not-found": "^2.3.24", + "@oclif/plugin-help": "^5.2.15", + "@oclif/plugin-not-found": "^2.3.34", "@oclif/plugin-update": "^3.1.16", - "@oclif/plugin-warn-if-update-available": "^2.0.40", + "@oclif/plugin-warn-if-update-available": "^2.0.46", "axios": "^0.27.2", "chalk": "^4.1.2", "dotenv": "^16.3.1" @@ -1886,10 +1967,29 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -2201,9 +2301,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2333,9 +2433,9 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "peer": true }, @@ -2446,7 +2546,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -2486,6 +2585,24 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -2595,6 +2712,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -2623,11 +2751,43 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dependencies": { "function-bind": "^1.1.2" }, @@ -2710,9 +2870,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -3464,9 +3624,9 @@ } }, "node_modules/node-abi": { - "version": "3.54.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", - "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", + "version": "3.55.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.55.0.tgz", + "integrity": "sha512-uPEjtyh2tFEvWYt4Jw7McOD5FPcHkcxm/tHZc5PWaDB3JYq0rGFUbgaAK+CT5pYpQddBfsZVWI08OwoRfdfbcQ==", "dev": true, "dependencies": { "semver": "^7.3.5" @@ -3495,6 +3655,14 @@ } } }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-treeify": { "version": "1.1.33", "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", @@ -3757,6 +3925,17 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/picomatch-browser": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/picomatch-browser/-/picomatch-browser-2.2.6.tgz", + "integrity": "sha512-0ypsOQt9D4e3hziV8O4elD9uN0z/jtUEfxVRtNaAAtXIyUx9m/SzlO020i8YNL2aL/E6blOvvHQcin6HZlFy/w==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pkg": { "version": "5.8.1", "resolved": "https://registry.npmjs.org/pkg/-/pkg-5.8.1.tgz", @@ -3915,6 +4094,20 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.11.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", + "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -3940,6 +4133,11 @@ "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" }, + "node_modules/rate-limiter-flexible": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.1.tgz", + "integrity": "sha512-2/dGHpDFpeA0+755oUkW+EKyklqLS9lu0go9pDsbhqQjZcxfRyJ6LA4JI0+HAdZ2bemD/oOjUeZQB2lCZqXQfQ==" + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -4144,9 +4342,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4157,6 +4355,22 @@ "node": ">=10" } }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4178,6 +4392,23 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", @@ -4321,12 +4552,15 @@ } }, "node_modules/streamx": { - "version": "2.15.6", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", - "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz", + "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==", "dependencies": { "fast-fifo": "^1.1.0", "queue-tick": "^1.0.1" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { @@ -4439,9 +4673,9 @@ } }, "node_modules/tar-stream": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.6.tgz", - "integrity": "sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -4518,12 +4752,12 @@ } }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" @@ -4733,9 +4967,9 @@ } }, "node_modules/winston-transport": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", - "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", + "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -4773,6 +5007,11 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, + "node_modules/xcase": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/xcase/-/xcase-2.0.1.tgz", + "integrity": "sha512-UmFXIPU+9Eg3E9m/728Bii0lAIuoc+6nbrNUKaRPJOFp91ih44qqGlWtxMB6kXFrRD6po+86ksHM5XHCfk6iPw==" + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4853,9 +5092,9 @@ } }, "node_modules/zod-validation-error": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.0.0.tgz", - "integrity": "sha512-x+agsJJG9rvC7axF0xqTEdZhJkLHyIZkdOAWDJSmwGPzxNHMHwtU6w2yDOAAP6yuSfTAUhAMJRBfhVGY64ySEQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-3.0.2.tgz", + "integrity": "sha512-21xGaDmnU7lJZ4J63n5GXWqi+rTzGy3gDHbuZ1jP6xrK/DEQGyOqs/xW7eH96tIfCOYm+ecCuT0bfajBRKEVUw==", "engines": { "node": ">=18.0.0" }, diff --git a/NodeApp/package.json b/NodeApp/package.json index 3ae9cf17b1c7c2932e3ed62e9ead6f9a7e6f0339..cea130b65abd9cad9e60bdc1f1afc9c6ccdc1a94 100644 --- a/NodeApp/package.json +++ b/NodeApp/package.json @@ -1,7 +1,7 @@ { "name" : "dojo_cli", "description" : "CLI of the Dojo project", - "version" : "3.4.2", + "version" : "3.5.0", "license" : "AGPLv3", "author" : "Michaël Minelli <dojo@minelli.me>", "main" : "dist/app.js", @@ -33,6 +33,7 @@ "test" : "echo \"Error: no test specified\" && exit 1" }, "dependencies" : { + "@gitbeaker/rest" : "^39.34.3", "appdata-path" : "^1.0.0", "axios" : "^1.6.5", "boxen" : "^5.1.2", diff --git a/NodeApp/src/commander/CommanderApp.ts b/NodeApp/src/commander/CommanderApp.ts index 03814c8a2394417570e34c1cde3618c7e89cfd2b..f32b3d79c7495f13c06da4940f20b27ab0feec0f 100644 --- a/NodeApp/src/commander/CommanderApp.ts +++ b/NodeApp/src/commander/CommanderApp.ts @@ -26,6 +26,7 @@ class CommanderApp { sortSubcommands : true }) .option('-H, --host <string>', 'override the Dojo API endpoint', ClientsSharedConfig.apiURL) + .option('-I, --interactive', 'show interactive interface when available', Config.interactiveMode) .addOption(new Option('--debug').hideHelp()) .hook('preAction', () => { this.warnDevelopmentVersion(); @@ -37,6 +38,10 @@ class CommanderApp { ClientsSharedConfig.apiURL = this.program.opts().host; }); + this.program.on('option:interactive', () => { + Config.interactiveMode = this.program.opts().interactive; + }); + this.program.on('option:debug', () => { SharedConfig.debug = true; }); diff --git a/NodeApp/src/commander/assignment/AssignmentCommand.ts b/NodeApp/src/commander/assignment/AssignmentCommand.ts index 90ae6167deaece3339766cc3f8a7b090263d2e79..b54c2cb00fcd0622f818ed9c621b823d9b7699e4 100644 --- a/NodeApp/src/commander/assignment/AssignmentCommand.ts +++ b/NodeApp/src/commander/assignment/AssignmentCommand.ts @@ -1,9 +1,10 @@ -import CommanderCommand from '../CommanderCommand'; -import AssignmentCreateCommand from './subcommands/AssignmentCreateCommand'; -import AssignmentPublishCommand from './subcommands/AssignmentPublishCommand'; -import AssignmentUnpublishCommand from './subcommands/AssignmentUnpublishCommand'; -import AssignmentCheckCommand from './subcommands/AssignmentCheckCommand'; -import AssignmentRunCommand from './subcommands/AssignmentRunCommand'; +import CommanderCommand from '../CommanderCommand'; +import AssignmentCreateCommand from './subcommands/AssignmentCreateCommand'; +import AssignmentPublishCommand from './subcommands/AssignmentPublishCommand'; +import AssignmentUnpublishCommand from './subcommands/AssignmentUnpublishCommand'; +import AssignmentCheckCommand from './subcommands/AssignmentCheckCommand'; +import AssignmentRunCommand from './subcommands/AssignmentRunCommand'; +import AssignmentCorrectionCommand from './subcommands/correction/AssignmentCorrectionCommand'; class AssignmentCommand extends CommanderCommand { @@ -20,6 +21,7 @@ class AssignmentCommand extends CommanderCommand { AssignmentRunCommand.registerOnCommand(this.command); AssignmentPublishCommand.registerOnCommand(this.command); AssignmentUnpublishCommand.registerOnCommand(this.command); + AssignmentCorrectionCommand.registerOnCommand(this.command); } protected async commandAction(): Promise<void> { } diff --git a/NodeApp/src/commander/assignment/subcommands/correction/AssignmentCorrectionCommand.ts b/NodeApp/src/commander/assignment/subcommands/correction/AssignmentCorrectionCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f30a994e7fdcd0a773401db5daa36abba861579 --- /dev/null +++ b/NodeApp/src/commander/assignment/subcommands/correction/AssignmentCorrectionCommand.ts @@ -0,0 +1,23 @@ +import CommanderCommand from '../../../CommanderCommand'; +import AssignmentCorrectionLinkCommand from './subcommands/AssignmentCorrectionLinkCommand'; +import AssignmentCorrectionUpdateCommand from './subcommands/AssignmentCorrectionUpdateCommand'; + + +class AssignmentCorrectionCommand extends CommanderCommand { + protected commandName: string = 'correction'; + + protected defineCommand() { + this.command + .description('manage corrections of an assignment'); + } + + protected defineSubCommands() { + AssignmentCorrectionLinkCommand.registerOnCommand(this.command); + AssignmentCorrectionUpdateCommand.registerOnCommand(this.command); + } + + protected async commandAction(): Promise<void> { } +} + + +export default new AssignmentCorrectionCommand(); \ No newline at end of file diff --git a/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkCommand.ts b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d173206038be1262127faf618b74cb874022ffa --- /dev/null +++ b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkCommand.ts @@ -0,0 +1,10 @@ +import AssignmentCorrectionLinkUpdateCommand from './AssignmentCorrectionLinkUpdateCommand'; + + +class AssignmentCorrectionLinkCommand extends AssignmentCorrectionLinkUpdateCommand { + protected commandName: string = 'link'; + protected isUpdate: boolean = false; +} + + +export default new AssignmentCorrectionLinkCommand(); \ No newline at end of file diff --git a/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkUpdateCommand.ts b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkUpdateCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..cd7b4f8897678e3e43fe2bd6973a76f0ac61db94 --- /dev/null +++ b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionLinkUpdateCommand.ts @@ -0,0 +1,62 @@ +import CommanderCommand from '../../../../CommanderCommand'; +import chalk from 'chalk'; +import ora from 'ora'; +import DojoBackendManager from '../../../../../managers/DojoBackendManager'; +import SessionManager from '../../../../../managers/SessionManager'; +import Assignment from '../../../../../sharedByClients/models/Assignment'; + + +abstract class AssignmentCorrectionLinkUpdateCommand extends CommanderCommand { + protected abstract isUpdate: boolean; + + protected defineCommand() { + this.command + .description(this.isUpdate ? 'update a correction of an assignment' : 'link an exercise repo as a correction for an assignment') + .argument('<string>', 'id or url of the exercise that is the correction') + .requiredOption('-a, --assignment <string>', 'id or url of the assignment of the correction') + .action(this.commandAction.bind(this)); + } + + protected async commandAction(exerciseIdOrUrl: string, options: { assignment: string }): Promise<void> { + let assignment!: Assignment | undefined; + + // Check access + { + console.log(chalk.cyan('Please wait while we check access...')); + + const assignmentGetSpinner: ora.Ora = ora('Checking if assignment exists').start(); + assignment = await DojoBackendManager.getAssignment(options.assignment); + if ( !assignment ) { + assignmentGetSpinner.fail(`The assignment doesn't exists`); + return; + } + assignmentGetSpinner.succeed(`The assignment exists`); + + + const assignmentAccessSpinner: ora.Ora = ora('Checking assignment access').start(); + if ( assignment.staff.find(staff => staff.id === SessionManager.profile?.id) === undefined ) { + assignmentAccessSpinner.fail(`You are not in the staff of the assignment`); + return; + } + assignmentAccessSpinner.succeed(`You are in the staff of the assignment`); + + + const assignmentPublishedSpinner: ora.Ora = ora('Checking assignment').start(); + if ( !assignment.published ) { + assignmentPublishedSpinner.fail(`Assignment is not published`); + return; + } + assignmentPublishedSpinner.succeed(`Assignment is published`); + } + + // Link the exercise + { + console.log(chalk.cyan('Please wait while we link the exercise...')); + + await DojoBackendManager.linkUpdateCorrection(exerciseIdOrUrl, assignment, this.isUpdate); + } + } +} + + +export default AssignmentCorrectionLinkUpdateCommand; \ No newline at end of file diff --git a/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionUpdateCommand.ts b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionUpdateCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..88a9f48dfdce248137c857f945116e0be51d171e --- /dev/null +++ b/NodeApp/src/commander/assignment/subcommands/correction/subcommands/AssignmentCorrectionUpdateCommand.ts @@ -0,0 +1,10 @@ +import AssignmentCorrectionLinkUpdateCommand from './AssignmentCorrectionLinkUpdateCommand'; + + +class AssignmentCorrectionUpdateCommand extends AssignmentCorrectionLinkUpdateCommand { + protected commandName: string = 'update'; + protected isUpdate: boolean = true; +} + + +export default new AssignmentCorrectionUpdateCommand(); \ No newline at end of file diff --git a/NodeApp/src/commander/exercise/ExerciseCommand.ts b/NodeApp/src/commander/exercise/ExerciseCommand.ts index a475d4f91bf8d7a39bf74acc7c131cf32b7564f4..2a93b7a40c66845444f75d2453f731ab8fa6925f 100644 --- a/NodeApp/src/commander/exercise/ExerciseCommand.ts +++ b/NodeApp/src/commander/exercise/ExerciseCommand.ts @@ -1,6 +1,7 @@ -import CommanderCommand from '../CommanderCommand'; -import ExerciseCreateCommand from './subcommands/ExerciseCreateCommand'; -import ExerciseRunCommand from './subcommands/ExerciseRunCommand'; +import CommanderCommand from '../CommanderCommand'; +import ExerciseCreateCommand from './subcommands/ExerciseCreateCommand'; +import ExerciseRunCommand from './subcommands/ExerciseRunCommand'; +import ExerciseCorrectionCommand from './subcommands/ExerciseCorrectionCommand'; class ExerciseCommand extends CommanderCommand { @@ -14,6 +15,7 @@ class ExerciseCommand extends CommanderCommand { protected defineSubCommands() { ExerciseCreateCommand.registerOnCommand(this.command); ExerciseRunCommand.registerOnCommand(this.command); + ExerciseCorrectionCommand.registerOnCommand(this.command); } protected async commandAction(): Promise<void> { } diff --git a/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts new file mode 100644 index 0000000000000000000000000000000000000000..0704ebfa5598e601f2575f80aa7fa8e24c221f02 --- /dev/null +++ b/NodeApp/src/commander/exercise/subcommands/ExerciseCorrectionCommand.ts @@ -0,0 +1,76 @@ +import CommanderCommand from '../../CommanderCommand'; +import ora from 'ora'; +import DojoBackendManager from '../../../managers/DojoBackendManager'; +import Config from '../../../config/Config'; +import Assignment from '../../../sharedByClients/models/Assignment'; +import inquirer from 'inquirer'; +import open from 'open'; +import chalk from 'chalk'; + + +type CorrectionResume = { name: string, value: string } + + +class ExerciseCorrectionCommand extends CommanderCommand { + protected commandName: string = 'correction'; + + protected defineCommand() { + this.command + .description('link an exercise repo as a correction for an assignment') + .requiredOption('-a, --assignment <string>', 'id or url of the assignment of the correction') + .action(this.commandAction.bind(this)); + } + + protected async commandAction(options: { assignment: string }): Promise<void> { + const assignmentGetSpinner: ora.Ora = ora('Fetching assignment data').start(); + const assignment = await DojoBackendManager.getAssignment(options.assignment); + if ( !assignment ) { + assignmentGetSpinner.fail(`The assignment doesn't exists`); + return; + } + + if ( assignment.corrections && assignment.corrections.length > 0 ) { + Config.interactiveMode ? await this.showCorrectionsInteractive(assignment, assignmentGetSpinner) : this.showCorrections(assignment, assignmentGetSpinner); + } else { + assignmentGetSpinner.fail(`The assignment doesn't have any corrections yet`); + return; + } + } + + private getCorrections(assignment: Assignment): Array<CorrectionResume> { + return assignment.corrections.map(correction => { + return { + name : correction.name.replace(correction.assignmentName, '').split('-')[2].trim(), + value: correction.correctionCommit!.web_url?.replace('/commit/', '/tree/') ?? '' + }; + }); + } + + private showCorrections(assignment: Assignment, spinner: ora.Ora) { + spinner.succeed(`Here are corrections of the assignment '${ assignment.name }':`); + + this.getCorrections(assignment).forEach(correction => { + console.log(chalk.green(`- ${ correction.name }`)); + console.log(` ${ correction.value }`); + }); + } + + private async showCorrectionsInteractive(assignment: Assignment, spinner: ora.Ora) { + spinner.stop(); + + const correctionUrl: string = (await inquirer.prompt({ + name : 'correctionUrl', + message: 'Which correction do you want to consult? (use arrow keys then enter)', + type : 'list', + choices: this.getCorrections(assignment), + default: false + })).correctionUrl; + + console.log(chalk.green(correctionUrl)); + + open(correctionUrl).then(); + } +} + + +export default new ExerciseCorrectionCommand(); \ No newline at end of file diff --git a/NodeApp/src/config/Config.ts b/NodeApp/src/config/Config.ts index b0d2df81c57e001728eeda4166110d153c2eaf96..375f0cf22034eb73d958b8d711efe8fa9af9eb72 100644 --- a/NodeApp/src/config/Config.ts +++ b/NodeApp/src/config/Config.ts @@ -30,6 +30,8 @@ class Config { neededFiles: Array<string> }; + public interactiveMode: boolean; + constructor() { this.localConfig = { folder : getAppDataPath('DojoCLI'), @@ -62,6 +64,8 @@ class Config { this.exercise = { neededFiles: JSON.parse(process.env.EXERCISE_NEEDED_FILES || '[]') }; + + this.interactiveMode = process.env.INTERACTIVE_MODE === 'true'; } } diff --git a/NodeApp/src/helpers/AccessesHelper.ts b/NodeApp/src/helpers/AccessesHelper.ts index e49e5819e59c74042fb5f23f79ace5587ae128c3..c9ff5e1bdaa823ca011eba7fa057e1c0b949a74e 100644 --- a/NodeApp/src/helpers/AccessesHelper.ts +++ b/NodeApp/src/helpers/AccessesHelper.ts @@ -3,25 +3,34 @@ import GitlabManager from '../managers/GitlabManager'; class AccessesHelper { - async checkStudent(): Promise<boolean> { + async checkStudent(testGitlab: boolean = false): Promise<boolean> { const sessionResult = await SessionManager.testSession(true, [ 'student' ]); if ( !sessionResult ) { return false; } - return (await GitlabManager.testToken(true)).every(result => result); + if ( testGitlab ) { + return (await GitlabManager.testToken(true)).every(result => result); + } else { + return true; + } } - - async checkTeachingStaff(): Promise<boolean> { + + async checkTeachingStaff(testGitlab: boolean = false): Promise<boolean> { const sessionResult = await SessionManager.testSession(true, [ 'teachingStaff' ]); if ( !sessionResult || !sessionResult.teachingStaff ) { return false; } - return (await GitlabManager.testToken(true)).every(result => result); + if ( testGitlab ) { + return (await GitlabManager.testToken(true)).every(result => result); + } else { + return true; + } } } + export default new AccessesHelper(); \ No newline at end of file diff --git a/NodeApp/src/managers/DojoBackendManager.ts b/NodeApp/src/managers/DojoBackendManager.ts index b8e8a41ec1beb1172244b281c61d658dc2c923ec..fcd749df9a44d151c202498cb8d5a8dfe5f2df2a 100644 --- a/NodeApp/src/managers/DojoBackendManager.ts +++ b/NodeApp/src/managers/DojoBackendManager.ts @@ -192,6 +192,49 @@ class DojoBackendManager { throw error; } } + + public async linkUpdateCorrection(exerciseIdOrUrl: string, assignment: Assignment, isUpdate: boolean, verbose: boolean = true): Promise<boolean> { + const spinner: ora.Ora = ora(`${ isUpdate ? 'Updating' : 'Linking' } correction`); + + if ( verbose ) { + spinner.start(); + } + + try { + const axiosFunction = isUpdate ? axios.patch : axios.post; + const route = isUpdate ? ApiRoute.ASSIGNMENT_CORRECTION_UPDATE : ApiRoute.ASSIGNMENT_CORRECTION_LINK; + + await axiosFunction(this.getApiUrl(route).replace('{{assignmentNameOrUrl}}', encodeURIComponent(assignment.name)).replace('{{exerciseIdOrUrl}}', encodeURIComponent(exerciseIdOrUrl)), { + exerciseIdOrUrl: exerciseIdOrUrl + }); + + if ( verbose ) { + spinner.succeed(`Correction ${ isUpdate ? 'updated' : 'linked' }`); + } + + return true; + } catch ( error ) { + if ( verbose ) { + if ( error instanceof AxiosError ) { + if ( error.response?.data ) { + if ( error.response.data.code === DojoStatusCode.ASSIGNMENT_EXERCISE_NOT_RELATED ) { + spinner.fail(`The exercise does not belong to the assignment.`); + } else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_ALREADY_EXIST ) { + spinner.fail(`This exercise is already labelled as a correction. If you want to update it, please use the update command.`); + } else if ( error.response.data.code === DojoStatusCode.EXERCISE_CORRECTION_NOT_EXIST ) { + spinner.fail(`The exercise is not labelled as a correction so it's not possible to update it.`); + } + } else { + spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error.response?.statusText }`); + } + } else { + spinner.fail(`Correction ${ isUpdate ? 'update' : 'link' } error: ${ error }`); + } + } + + return false; + } + } } diff --git a/NodeApp/src/managers/SessionManager.ts b/NodeApp/src/managers/SessionManager.ts index 4f1d25d39af634dec36a96f95be22fd5591011c2..b5175f8598955b32b9a1d2a4b0404e716e422926 100644 --- a/NodeApp/src/managers/SessionManager.ts +++ b/NodeApp/src/managers/SessionManager.ts @@ -38,11 +38,11 @@ class LoginServer { if ( req.url?.match(Config.login.server.route) ) { const urlParts = req.url.split('='); if ( urlParts.length > 0 ) { - this.events.emit('code', urlParts[1]); - res.writeHead(HttpStatusCode.Ok, { 'Content-Type': 'text/html' }); res.write(`<html lang="en"><body><h1 style="color: green">DojoCLI login successful</h1><h3>You can close this window.</h3></body></html>`); res.end(); + + this.events.emit('code', urlParts[1]); return; } @@ -66,6 +66,7 @@ class LoginServer { stop() { try { this.server.close(); + this.server.closeAllConnections(); this.events.emit('stopped'); } catch ( error ) { this.events.emit('error', error); diff --git a/NodeApp/src/shared b/NodeApp/src/shared index 75f67b647da34337f3b220cacf78b2115d6022bc..9e3f29d2f313ef96944a199da0db39f1827c496a 160000 --- a/NodeApp/src/shared +++ b/NodeApp/src/shared @@ -1 +1 @@ -Subproject commit 75f67b647da34337f3b220cacf78b2115d6022bc +Subproject commit 9e3f29d2f313ef96944a199da0db39f1827c496a diff --git a/NodeApp/src/sharedByClients b/NodeApp/src/sharedByClients index 098c6d20f6ed84240c086b979b56afd598fdfea4..4efff1c5127c6f84104016d7041d0cf281d981f8 160000 --- a/NodeApp/src/sharedByClients +++ b/NodeApp/src/sharedByClients @@ -1 +1 @@ -Subproject commit 098c6d20f6ed84240c086b979b56afd598fdfea4 +Subproject commit 4efff1c5127c6f84104016d7041d0cf281d981f8