From 9db22efc83a496503e7a72674a674885925776cb Mon Sep 17 00:00:00 2001 From: Astyax Nourel Date: Mon, 12 Jul 2021 01:16:49 +0200 Subject: [PATCH] migrating to Typescript --- .gitignore | 2 + BackEnd/configs/api_code.js | 8 - BackEnd/configs/index.js | 3 - BackEnd/lib/server_functions.js | 441 ------------------ BackEnd/nodemon.json | 5 + BackEnd/package-lock.json | 285 +++++++---- BackEnd/package.json | 14 +- BackEnd/routes/api/index.js | 21 - BackEnd/{app.js => src/app.ts} | 18 +- .../clients/swiftClient.ts} | 6 +- BackEnd/src/configs/api_code.ts | 8 + BackEnd/{ => src}/configs/default_index.json | 0 BackEnd/src/configs/index.ts | 2 + .../configs/log_message.ts} | 4 +- BackEnd/{configs/os.js => src/configs/os.ts} | 4 +- .../passport.js => src/configs/passport.ts} | 5 +- BackEnd/{lib/errors.js => src/lib/errors.ts} | 12 +- .../lib/global_functions.ts} | 28 +- .../lib/log_functions.ts} | 30 +- BackEnd/src/lib/server_functions.ts | 382 +++++++++++++++ .../lib/upload_functions.ts} | 276 +++++------ .../lib/user_functions.ts} | 16 +- BackEnd/{models/Log.js => src/models/Log.ts} | 2 +- .../Server.js => src/models/Server.ts} | 32 +- .../{models/User.js => src/models/User.ts} | 94 ++-- BackEnd/src/routes/api/index.ts | 27 ++ .../routes/api/profiles.ts} | 21 +- .../server.js => src/routes/api/server.ts} | 88 ++-- .../upload.js => src/routes/api/upload.ts} | 174 +++---- .../api/users.js => src/routes/api/users.ts} | 94 ++-- .../{routes/auth.js => src/routes/auth.ts} | 11 +- .../{routes/index.js => src/routes/index.ts} | 0 BackEnd/tsconfig-build.json | 6 + BackEnd/tsconfig.json | 25 + 34 files changed, 1136 insertions(+), 1008 deletions(-) delete mode 100644 BackEnd/configs/api_code.js delete mode 100644 BackEnd/configs/index.js delete mode 100644 BackEnd/lib/server_functions.js create mode 100644 BackEnd/nodemon.json delete mode 100644 BackEnd/routes/api/index.js rename BackEnd/{app.js => src/app.ts} (79%) rename BackEnd/{clients/swiftClient.js => src/clients/swiftClient.ts} (68%) create mode 100644 BackEnd/src/configs/api_code.ts rename BackEnd/{ => src}/configs/default_index.json (100%) create mode 100644 BackEnd/src/configs/index.ts rename BackEnd/{configs/log_message.js => src/configs/log_message.ts} (96%) rename BackEnd/{configs/os.js => src/configs/os.ts} (86%) rename BackEnd/{configs/passport.js => src/configs/passport.ts} (79%) rename BackEnd/{lib/errors.js => src/lib/errors.ts} (86%) rename BackEnd/{lib/global_functions.js => src/lib/global_functions.ts} (59%) rename BackEnd/{lib/log_functions.js => src/lib/log_functions.ts} (51%) create mode 100644 BackEnd/src/lib/server_functions.ts rename BackEnd/{lib/upload_functions.js => src/lib/upload_functions.ts} (74%) rename BackEnd/{lib/user_functions.js => src/lib/user_functions.ts} (51%) rename BackEnd/{models/Log.js => src/models/Log.ts} (92%) rename BackEnd/{models/Server.js => src/models/Server.ts} (61%) rename BackEnd/{models/User.js => src/models/User.ts} (60%) create mode 100644 BackEnd/src/routes/api/index.ts rename BackEnd/{routes/api/profiles.js => src/routes/api/profiles.ts} (68%) rename BackEnd/{routes/api/server.js => src/routes/api/server.ts} (86%) rename BackEnd/{routes/api/upload.js => src/routes/api/upload.ts} (79%) rename BackEnd/{routes/api/users.js => src/routes/api/users.ts} (84%) rename BackEnd/{routes/auth.js => src/routes/auth.ts} (78%) rename BackEnd/{routes/index.js => src/routes/index.ts} (100%) create mode 100644 BackEnd/tsconfig-build.json create mode 100644 BackEnd/tsconfig.json diff --git a/.gitignore b/.gitignore index 92ef0c2..c423139 100644 --- a/.gitignore +++ b/.gitignore @@ -86,4 +86,6 @@ /BackEnd/.idea /BackEnd/configs/OS.js +/BackEnd/src/configs/OS.ts /BackEnd/dist + diff --git a/BackEnd/configs/api_code.js b/BackEnd/configs/api_code.js deleted file mode 100644 index 61b853e..0000000 --- a/BackEnd/configs/api_code.js +++ /dev/null @@ -1,8 +0,0 @@ -var api_code = { - ok: '204', - error: '422', - forbidden: '401', - not_found: '404', -}; - -module.exports = api_code; diff --git a/BackEnd/configs/index.js b/BackEnd/configs/index.js deleted file mode 100644 index 1bf9d6a..0000000 --- a/BackEnd/configs/index.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - secret: process.env.NODE_ENV === 'production' ? process.env.SECRET : 'secret' -}; diff --git a/BackEnd/lib/server_functions.js b/BackEnd/lib/server_functions.js deleted file mode 100644 index a0218b6..0000000 --- a/BackEnd/lib/server_functions.js +++ /dev/null @@ -1,441 +0,0 @@ -const k8s = require('@kubernetes/client-node'); -const kc = new k8s.KubeConfig(); -kc.loadFromDefault(); -const k8sApiDeploy = kc.makeApiClient(k8s.AppsV1Api); -const k8sApi = kc.makeApiClient(k8s.CoreV1Api); -const k8sApiIngress = kc.makeApiClient(k8s.ExtensionsV1beta1Api); - -k8sApiIngress.defaultHeaders = { - 'Content-Type': 'application/strategic-merge-patch+json', - ...k8sApiIngress.defaultHeaders, -}; -var swiftClient = require('../clients/swiftClient'); -var OS = require('../configs/OS'); - -const global_functions = require('./global_functions'); -const upload_functions = require('./upload_functions'); -const podLabelPrefix = 'app='; -const intervalTime = 5000; - -async function _createNamespacedDeployment(deployment, namespace) { - return k8sApiDeploy.createNamespacedDeployment(namespace, deployment); -} - -async function _readNamespacedDeployment(slug, namespace) { - return k8sApiDeploy.readNamespacedDeployment(slug, namespace); -}; - -/** - * Return a promise with the list of pods found - * an empty list mean no pods found - */ -async function _listNamespacedPod(slug, namespace, verbose = false) { - return k8sApi.listNamespacedPod(namespace, undefined, undefined, undefined, - undefined, podLabelPrefix + slug) - .then(res => (verbose) ? res : res.body.items); -} - -/** - * Find the first pod in the list of pods found - * if the list is empty, return an rejected promise - */ -async function _readNamespacedPod(slug, namespace) { - return _listNamespacedPod(slug, namespace) - .then(items => { - if (items.length < 1) - throw new Error('Pod not found'); - return items[0]; - }); -} - -async function _readNamespacedPodLog(slug, namespace, verbose = false) { - return _readNamespacedPod(slug, namespace) - .then(pod => pod.metadata.name) - .then(name => k8sApi.readNamespacedPodLog(name, namespace)) - .then(res => (verbose) ? res : res.body); -} - -async function _tryGetTeacherToken(slug, namespace) { - return _readNamespacedPodLog(slug, namespace) - .then(log => global_functions.tryFindTeacherToken(log)); -} - -async function _catchTeacherToken(slug, namespace) { - async function watchCatchTeacherToken() { - let timedWatchCatch = () => global_functions.timedRun(watchCatchTeacherToken, intervalTime); - - return _tryGetTeacherToken(slug, namespace) - .catch(err => { - if (err === global_functions.tokenObj.errorNotFound) { - console.log("Token not found, retrying..."); - return timedWatchCatch(); - } else { - throw err; - } - }); - } - - return watchCatchTeacherToken(); -} - -async function _createNamespacedService(service, namespace) { - return k8sApi.createNamespacedService(namespace, service); -}; - -async function _patchNamespacedIngress(_spec, namespace) { - return k8sApiIngress.patchNamespacedIngress('learn-ocaml', namespace, { spec: _spec }); -}; - -async function _createNamespacedIngress(rule, namespace) { - return new Promise(function (resolve, reject) { - k8sApiIngress.readNamespacedIngress('learn-ocaml', namespace, 'true').then( - (response) => { - response.body.spec.rules.push(rule); - return resolve(_patchNamespacedIngress(response.body.spec, namespace)); - }, - (err) => { - console.log('Error!: ' + JSON.stringify(err)); - return reject(err); - }, - ); - }); -}; - -function _createObjectDeployment(slug) { - return { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - name: slug, - labels: { - app: slug - } - }, - spec: { - replicas: 1, - selector: { - matchLabels: { - app: slug - } - }, - template: { - metadata: { - labels: { - app: slug - } - }, - spec: { - containers: [{ - name: 'learn-ocaml', - image: 'ocamlsf/learnocaml-essok-dockerfile:latest', - ports: [{ - containerPort: 8080 - }], - env: [{ - name: 'OS_AUTH_URL', - value: OS.authUrl - }, - { - name: 'ST_AUTH_VERION', - value: OS.identityApiVersion - }, - { - name: 'OS_USERNAME', - value: OS.username - }, - { - name: 'OS_USER_DOMAIN_NAME', - value: OS.domainName - }, - { - name: 'OS_PASSWORD', - value: OS.password - }, - { - name: 'OS_PROJECT_NAME', - value: OS.projectName - }, - { - name: 'OS_PROJECT_DOMAIN_NAME', - value: OS.domainName - }, - { - name: 'OS_REGION_NAME', - value: OS.region - } - ], - args: [slug] - }], - terminationGracePeriodSeconds: 900 - } - } - } - } -} - -function _createObjectService(slug) { - return { - apiVersion: 'v1', - kind: 'Service', - metadata: { - name: slug, - labels: { - app: slug - } - }, - spec: { - type: 'ClusterIP', - selector: { - app: slug - }, - ports: [{ - name: 'http', - port: 80, - targetPort: 8080 - }] - } - } -} - -function _createObjectRule(slug, username) { - return { - // TODO: remove hard coded URL - host: username + '.' + slug + '.learn-ocaml.org', - http: { - paths: [{ - backend: { - serviceName: slug, - servicePort: 80 - } - }] - } - } -} - -function _createObjectContainer(slug) { - return { - name: slug, - metadata: {} - } -} - -function _createkubelink(slug, username, namespace) { - return new Promise(function (resolve, reject) { - var deployment = _createObjectDeployment(slug); - var service = _createObjectService(slug); - var rule = _createObjectRule(slug, username); - _createNamespacedDeployment(deployment, namespace).then((response) => { - _createNamespacedService(service, namespace).then((response) => { - _createNamespacedIngress(rule, namespace).then((response) => { - console.log('kubelink created'); - return resolve('done'); - }, (err) => { - return reject(err); - }); - }, (err) => { - return reject(err); - }); - }, - (err) => { - return reject(err); - }); - }); -}; - -function _createSwiftContainer(slug) { - return new Promise(function (resolve, reject) { - swiftClient.createContainer(_createObjectContainer(slug), function (err, container) { - if (err) return reject(err); - return resolve(container); - }); - }); -}; - -function _getSwiftContainer(slug) { - return new Promise(function (resolve, reject) { - swiftClient.getContainers(function (err, containers) { - if (err) return reject(err); - else { - for (let i = 0; i < containers.length; i++) { - if (containers[i].name === slug) { - return resolve(containers[i]); - } else { - if (i === containers.length - 1) { - return reject('not found'); - } - } - } - } - }); - }); -}; - -function _copySwiftContainerFile(containerSrc, containerDst, file) { - return new Promise((resolve, reject) => { - swiftClient.copy({ - sourceContainer: containerSrc, - destinationContainer: containerDst, - sourceFile: file, - destinationFile: file - }, (err, res) => { - if (err !== null) - reject(err); - resolve(res); - }); - }); -} - -function _copySwiftContainer(containerSrc, containerDst) { - return new Promise((resolve, reject) => { - swiftClient.getFiles(containerSrc, (err, files) => { - if (err !== null) - reject(err); - files = files.map(file => _copySwiftContainerFile(containerSrc, - containerDst, - file)); - Promise.all(files).then(resolve, reject); - }); - }); -} - -function _destroySwiftContainer(slug) { - return new Promise(function (resolve, reject) { - _getSwiftContainer(slug).then(function (response) { - swiftClient.destroyContainer(response, function (err, result) { - if (err) return reject(err); - return resolve(result); - }); - }, (err) => { - console.log('already deleted'); - return resolve('already deleted'); - }); - }); -}; - -function _removeIngressFile(rules, slug) { - return new Promise(function (resolve, reject) { - - for (let index = 0; index < rules.length; index++) { - if (rules[index].http.paths[0].backend.serviceName === slug) { - rules.splice(index, 1); - return resolve('done'); - } else { - if (index === rules.length - 1) { - return resolve('already deleted'); - } - } - } - }); -}; - -function _deleteNamespacedIngress(slug, namespace) { - return new Promise(function (resolve, reject) { - k8sApiIngress.readNamespacedIngress('learn-ocaml', namespace, 'true').then( - (response) => { - var rules = response.body.spec.rules; - console.log('Ingress read'); - console.log('rule find : ' + rules); - _removeIngressFile(rules, slug).then(() => { - console.log('Ingress removed'); - _patchNamespacedIngress(response.body.spec, namespace).then(() => { - console.log('Ingress patched'); - return resolve('done'); - }, (err) => { - return reject(err); - }); - }, (err) => { - return reject(err); - }); - }, (err) => { - return reject(err); - }); - }); -}; - -async function _deleteNamespacedService(slug, namespace) { - return new Promise(function (resolve, reject) { - k8sApi.readNamespacedService(slug, namespace).then((response) => { - return resolve(k8sApi.deleteNamespacedService(slug, namespace)); - }, (err) => { - console.log('Service doesnt exist'); - return resolve('Service doesnt exist'); - }); - }); -}; - -async function _deleteNamespacedDeployment(slug, namespace, waitPodDie = true) { - async function watchPodDie() { - let timedWatchRun = () => global_functions.timedRun(watchPodDie, intervalTime); - return _readNamespacedPod(slug, namespace) - .then(_ => timedWatchRun()) - .catch(_ => true); - } - - return k8sApiDeploy.deleteNamespacedDeployment(slug, namespace) - .then(_ => (waitPodDie) ? watchPodDie() : true) - .catch(_ => false); -}; - -function _removekubelink(slug, namespace) { - return new Promise(function (resolve, reject) { - _deleteNamespacedIngress(slug, namespace).then((response) => { - console.log('ingress removed'); - _deleteNamespacedService(slug, namespace).then((response) => { - console.log('service removed'); - _deleteNamespacedDeployment(slug, namespace).then((response) => { - console.log('deployment removed'); - return resolve('done'); - }, (err) => { - return reject(err); - }); - }, (err) => { - return reject(err); - }); - }, (err) => { - return reject(err); - }); - }); -}; - -function _delete(slug, namespace, path) { - return new Promise(function (resolve, reject) { - _removekubelink(slug, namespace).then((response) => { - console.log('kubelink removed'); - _destroySwiftContainer(slug).then((response) => { - console.log('swift container removed'); - upload_functions.removeDir(path).then(_ => { - console.log('server deleted'); - return resolve('done'); - }, (err) => { - console.log(err); - return reject(err); - }); - }, (err) => { - console.log(err); - return reject(err); - }); - }, (err) => { - console.log(err); - return reject(err); - }); - }); -} - -var server_functions = { - createNamespacedDeployment: _createNamespacedDeployment, - copySwiftContainer: _copySwiftContainer, - createSwiftContainer: _createSwiftContainer, - shut_on: _createkubelink, - shut_off: _removekubelink, - delete: _delete, - readNamespacedPodLog: _readNamespacedPodLog, - tryGetTeacherToken: _tryGetTeacherToken, - catchTeacherToken: _catchTeacherToken, - /* Used to debug - createNamespacedIngress: _createNamespacedIngress, - deleteNamespacedIngress: _deleteNamespacedIngress, - createObjectRule: _createObjectRule, - */ -}; - -module.exports = server_functions; diff --git a/BackEnd/nodemon.json b/BackEnd/nodemon.json new file mode 100644 index 0000000..27a8918 --- /dev/null +++ b/BackEnd/nodemon.json @@ -0,0 +1,5 @@ +{ + "events": { + "start": "clear" + } +} diff --git a/BackEnd/package-lock.json b/BackEnd/package-lock.json index a73984a..3422c2d 100644 --- a/BackEnd/package-lock.json +++ b/BackEnd/package-lock.json @@ -29,7 +29,7 @@ "jsonwebtoken": "8.5.1", "method-override": "3.0.0", "methods": "1.1.2", - "mongoose": "5.11.11", + "mongoose": "^5.13.2", "mongoose-unique-validator": "2.0.3", "morgan": "^1.10.0", "multer": "^1.4.2", @@ -43,6 +43,7 @@ "unzipper": "^0.10.11" }, "devDependencies": { + "@types/express": "^4.17.13", "newman": "^5.2.2", "nodemon": "^2.0.7" } @@ -235,6 +236,16 @@ "node": ">=10" } }, + "node_modules/@types/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, "node_modules/@types/bson": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", @@ -259,6 +270,38 @@ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", + "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "node_modules/@types/http-cache-semantics": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", @@ -277,6 +320,12 @@ "@types/node": "*" } }, + "node_modules/@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "node_modules/@types/minipass": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz", @@ -299,6 +348,18 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.50.tgz", "integrity": "sha512-vwX+/ija9xKc/z9VqMCdbf4WYcMTGsI0I/L/6shIF3qXURxZOhPQlPRHtjTpiNhAwn0paMJzlOQqw6mAGEQnTA==" }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, "node_modules/@types/request": { "version": "2.48.5", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", @@ -318,6 +379,16 @@ "@types/node": "*" } }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "node_modules/@types/stream-buffers": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.3.tgz", @@ -1242,9 +1313,9 @@ } }, "node_modules/bson": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", - "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", "engines": { "node": ">=0.6.19" } @@ -1484,7 +1555,6 @@ "anymatch": "^2.0.0", "async-each": "^1.0.1", "braces": "^2.3.2", - "fsevents": "^1.2.7", "glob-parent": "^3.1.0", "inherits": "^2.0.3", "is-binary-path": "^1.0.0", @@ -1633,7 +1703,6 @@ "integrity": "sha512-gnB85c3MGC7Nm9I/FkiasNBOKjOiO1RNuXXarQms37q4QMpWdlbBgD/VnOStA2faG1dpXMv31RFApjX1/QdgWQ==", "dev": true, "dependencies": { - "colors": "^1.1.2", "object-assign": "^4.1.0", "string-width": "^4.2.0" }, @@ -3788,7 +3857,6 @@ "minimist": "^1.2.5", "neo-async": "^2.6.0", "source-map": "^0.6.1", - "uglify-js": "^3.1.4", "wordwrap": "^1.0.0" }, "bin": { @@ -4720,7 +4788,6 @@ "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dependencies": { - "graceful-fs": "^4.1.6", "universalify": "^2.0.0" }, "optionalDependencies": { @@ -5523,16 +5590,15 @@ } }, "node_modules/mongodb": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", - "integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==", + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.8.tgz", + "integrity": "sha512-sDjJvI73WjON1vapcbyBD3Ao9/VN3TKYY8/QX9EPbs22KaCSrQ5rXo5ZZd44tWJ3wl3FlnrFZ+KyUtNH6+1ZPQ==", "dependencies": { "bl": "^2.2.1", "bson": "^1.1.4", "denque": "^1.4.1", - "require_optional": "^1.0.1", - "safe-buffer": "^5.1.2", - "saslprep": "^1.0.0" + "optional-require": "^1.0.3", + "safe-buffer": "^5.1.2" }, "engines": { "node": ">=4" @@ -5562,21 +5628,22 @@ } }, "node_modules/mongoose": { - "version": "5.11.11", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.11.tgz", - "integrity": "sha512-JgKKAosJf6medPOZi2LmO7sMz7Sg00mgjyPAKari3alzL+R/n8D+zKK29iGtJpNNtv9IKy14H37CWuiaZ7016w==", + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.2.tgz", + "integrity": "sha512-sBUKJGpdwZCq9102Lj6ZOaLcW4z/T4TI9aGWrNX5ZlICwChKWG4Wo5qriLImdww3H7bETPW9vYtSiADNlA4wSQ==", "dependencies": { "@types/mongodb": "^3.5.27", + "@types/node": "14.x || 15.x", "bson": "^1.1.4", "kareem": "2.3.2", - "mongodb": "3.6.3", + "mongodb": "3.6.8", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.8.3", - "mquery": "3.2.3", + "mquery": "3.2.5", "ms": "2.1.2", "regexp-clone": "1.0.0", "safe-buffer": "5.2.1", - "sift": "7.0.1", + "sift": "13.5.2", "sliced": "1.0.1" }, "engines": { @@ -5607,6 +5674,11 @@ "mongoose": "^5.2.1" } }, + "node_modules/mongoose/node_modules/@types/node": { + "version": "15.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.2.tgz", + "integrity": "sha512-dvMUE/m2LbXPwlvVuzCyslTEtQ2ZwuuFClDrOQ6mp2CenCg971719PTILZ4I6bTP27xfFFc+o7x2TkLuun/MPw==" + }, "node_modules/mongoose/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -5663,9 +5735,9 @@ } }, "node_modules/mquery": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz", - "integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz", + "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==", "dependencies": { "bluebird": "3.5.1", "debug": "3.1.0", @@ -5962,7 +6034,6 @@ "dependencies": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -6400,6 +6471,14 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/optional-require": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", + "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==", + "engines": { + "node": ">=4" + } + }, "node_modules/ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", @@ -7724,23 +7803,6 @@ "node": ">=0.8" } }, - "node_modules/require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "dependencies": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - } - }, - "node_modules/require_optional/node_modules/resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8116,9 +8178,9 @@ } }, "node_modules/sift": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", - "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", + "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" }, "node_modules/sigmund": { "version": "1.0.1", @@ -10243,6 +10305,16 @@ "defer-to-connect": "^2.0.0" } }, + "@types/body-parser": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.1.tgz", + "integrity": "sha512-a6bTJ21vFOGIkwM0kzh9Yr89ziVxq4vYH2fQ6N8AeipEzai/cFK6aGMArIkUeIdRIgpwQa+2bXiLuUJCpSf2Cg==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, "@types/bson": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", @@ -10267,6 +10339,38 @@ "resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz", "integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w==" }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.24.tgz", + "integrity": "sha512-3UJuW+Qxhzwjq3xhwXm2onQcFHn76frIYVbTu+kn24LFxI+dEhdfISDFovPB8VpEgW8oQCTpRuCe+0zJxB7NEA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, "@types/http-cache-semantics": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.0.tgz", @@ -10285,6 +10389,12 @@ "@types/node": "*" } }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, "@types/minipass": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@types/minipass/-/minipass-2.2.0.tgz", @@ -10307,6 +10417,18 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.50.tgz", "integrity": "sha512-vwX+/ija9xKc/z9VqMCdbf4WYcMTGsI0I/L/6shIF3qXURxZOhPQlPRHtjTpiNhAwn0paMJzlOQqw6mAGEQnTA==" }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, "@types/request": { "version": "2.48.5", "resolved": "https://registry.npmjs.org/@types/request/-/request-2.48.5.tgz", @@ -10326,6 +10448,16 @@ "@types/node": "*" } }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, "@types/stream-buffers": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/stream-buffers/-/stream-buffers-3.0.3.tgz", @@ -11072,9 +11204,9 @@ } }, "bson": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", - "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" }, "buffer": { "version": "4.9.2", @@ -14551,37 +14683,43 @@ } }, "mongodb": { - "version": "3.6.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.3.tgz", - "integrity": "sha512-rOZuR0QkodZiM+UbQE5kDsJykBqWi0CL4Ec2i1nrGrUI3KO11r6Fbxskqmq3JK2NH7aW4dcccBuUujAP0ERl5w==", + "version": "3.6.8", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.8.tgz", + "integrity": "sha512-sDjJvI73WjON1vapcbyBD3Ao9/VN3TKYY8/QX9EPbs22KaCSrQ5rXo5ZZd44tWJ3wl3FlnrFZ+KyUtNH6+1ZPQ==", "requires": { "bl": "^2.2.1", "bson": "^1.1.4", "denque": "^1.4.1", - "require_optional": "^1.0.1", + "optional-require": "^1.0.3", "safe-buffer": "^5.1.2", "saslprep": "^1.0.0" } }, "mongoose": { - "version": "5.11.11", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.11.11.tgz", - "integrity": "sha512-JgKKAosJf6medPOZi2LmO7sMz7Sg00mgjyPAKari3alzL+R/n8D+zKK29iGtJpNNtv9IKy14H37CWuiaZ7016w==", + "version": "5.13.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.13.2.tgz", + "integrity": "sha512-sBUKJGpdwZCq9102Lj6ZOaLcW4z/T4TI9aGWrNX5ZlICwChKWG4Wo5qriLImdww3H7bETPW9vYtSiADNlA4wSQ==", "requires": { "@types/mongodb": "^3.5.27", + "@types/node": "14.x || 15.x", "bson": "^1.1.4", "kareem": "2.3.2", - "mongodb": "3.6.3", + "mongodb": "3.6.8", "mongoose-legacy-pluralize": "1.0.2", "mpath": "0.8.3", - "mquery": "3.2.3", + "mquery": "3.2.5", "ms": "2.1.2", "regexp-clone": "1.0.0", "safe-buffer": "5.2.1", - "sift": "7.0.1", + "sift": "13.5.2", "sliced": "1.0.1" }, "dependencies": { + "@types/node": { + "version": "15.14.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.2.tgz", + "integrity": "sha512-dvMUE/m2LbXPwlvVuzCyslTEtQ2ZwuuFClDrOQ6mp2CenCg971719PTILZ4I6bTP27xfFFc+o7x2TkLuun/MPw==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -14634,9 +14772,9 @@ "integrity": "sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA==" }, "mquery": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.3.tgz", - "integrity": "sha512-cIfbP4TyMYX+SkaQ2MntD+F2XbqaBHUYWk3j+kqdDztPWok3tgyssOZxMHMtzbV1w9DaSlvEea0Iocuro41A4g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.5.tgz", + "integrity": "sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A==", "requires": { "bluebird": "3.5.1", "debug": "3.1.0", @@ -15188,6 +15326,11 @@ "p-any": "^3.0.0" } }, + "optional-require": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", + "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==" + }, "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", @@ -16242,22 +16385,6 @@ } } }, - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - }, - "dependencies": { - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16557,9 +16684,9 @@ } }, "sift": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", - "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + "version": "13.5.2", + "resolved": "https://registry.npmjs.org/sift/-/sift-13.5.2.tgz", + "integrity": "sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA==" }, "sigmund": { "version": "1.0.1", diff --git a/BackEnd/package.json b/BackEnd/package.json index 1b314a9..b0c8f37 100644 --- a/BackEnd/package.json +++ b/BackEnd/package.json @@ -2,14 +2,11 @@ "name": "essok-node", "version": "1.5.3", "description": "essok on node", - "main": "app.js", + "main": "app.ts", "scripts": { - "mongo:start": "docker run --name realworld-mongo -p 27017:27017 mongo & sleep 5", - "start": "pm2 start ./app.js -i 2", - "dev": "nodemon ./app.js --ignore ./uploads", - "test": "newman run ./tests/api-tests.postman.json -e ./tests/env-api-tests.postman.json", - "stop": "lsof -ti :3000 | xargs kill", - "mongo:stop": "docker stop realworld-mongo && docker rm realworld-mongo" + "build": "tsc -p tsconfig-build.json", + "nodemon": "nodemon src/app.ts --ignore uploads", + "dev": "NODE_ENV=development DOTENV_CONFIG_PATH=.env-dev npm run nodemon" }, "repository": { "type": "git", @@ -37,7 +34,7 @@ "jsonwebtoken": "8.5.1", "method-override": "3.0.0", "methods": "1.1.2", - "mongoose": "5.11.11", + "mongoose": "^5.13.2", "mongoose-unique-validator": "2.0.3", "morgan": "^1.10.0", "multer": "^1.4.2", @@ -51,6 +48,7 @@ "unzipper": "^0.10.11" }, "devDependencies": { + "@types/express": "^4.17.13", "newman": "^5.2.2", "nodemon": "^2.0.7" } diff --git a/BackEnd/routes/api/index.js b/BackEnd/routes/api/index.js deleted file mode 100644 index 237cb63..0000000 --- a/BackEnd/routes/api/index.js +++ /dev/null @@ -1,21 +0,0 @@ -var router = require('express').Router(); -router.use('/', require('./users')); -router.use('/profiles', require('./profiles')); -router.use('/servers', require('./server')); -router.use('/uploads', require('./upload')); - -router.use(function(err, req, res, next){ - if(err.name === 'ValidationError'){ - return res.status(422).json({ - errors: Object.keys(err.errors).reduce(function(errors, key){ - errors[key] = err.errors[key].message; - - return errors; - }, {}) - }); - } - - return next(err); -}); - -module.exports = router; \ No newline at end of file diff --git a/BackEnd/app.js b/BackEnd/src/app.ts similarity index 79% rename from BackEnd/app.js rename to BackEnd/src/app.ts index e890dbd..147c584 100644 --- a/BackEnd/app.js +++ b/BackEnd/src/app.ts @@ -1,7 +1,9 @@ +import express from 'express'; +import { AddressInfo } from 'net'; + const https = require('https'), path = require('path'), methods = require('methods'), - express = require('express'), bodyParser = require('body-parser'), session = require('express-session'), cors = require('cors'), @@ -41,7 +43,7 @@ if (!isProduction) { if (isProduction) { mongoose.connect(process.env.MONGODB_URI); } else { - mongoose.connect('mongodb://localhost/essok', { useNewUrlParser: true, useUnifiedTopology: true }); + mongoose.connect('mongodb://172.17.0.2/essok', { useNewUrlParser: true, useUnifiedTopology: true }); mongoose.set('useCreateIndex', true); mongoose.set('debug', true); } @@ -52,12 +54,12 @@ require('./models/Log'); require('./configs/passport'); /// catch 404 and forward to error handler -app.use(function (req, res, next) { +app.use(function (_req, res, next) { //set headers to allow cross origin request. res.header("Access-Control-Allow-Origin", 'http://localhost:4200'); res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS'); res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); - res.setHeader('Access-Control-Allow-Credentials', true); + res.setHeader('Access-Control-Allow-Credentials', "true"); next(); }); @@ -68,7 +70,8 @@ app.use(require('./routes')); // development error handler // will print stacktrace if (!isProduction) { - app.use(function (err, req, res, next) { + app.use(function (err : any, _req : express.Request, + res : express.Response, _next: express.NextFunction) { console.log(err.stack); res.status(err.status || 500); @@ -84,7 +87,8 @@ if (!isProduction) { // production error handler // no stacktraces leaked to user -app.use(function (err, req, res, next) { +app.use(function (err : any, _req : express.Request, + res : express.Response, _next : express.NextFunction) { res.status(err.status || 500); res.json({ 'errors': { @@ -96,7 +100,7 @@ app.use(function (err, req, res, next) { // finally, let's start our server... var server = app.listen(process.env.PORT || 3000, function () { - console.log('Listening on port ' + server.address().port); + console.log('Listening on port ' + (server.address() as AddressInfo).port); }); server.setTimeout(30 * 60 * 1000); diff --git a/BackEnd/clients/swiftClient.js b/BackEnd/src/clients/swiftClient.ts similarity index 68% rename from BackEnd/clients/swiftClient.js rename to BackEnd/src/clients/swiftClient.ts index c7b6712..b078bd2 100644 --- a/BackEnd/clients/swiftClient.js +++ b/BackEnd/src/clients/swiftClient.ts @@ -1,7 +1,7 @@ var openstack = require('pkgcloud'); -var OS = require('../configs/OS'); +import { OS } from '../configs/OS'; -var swiftClient = openstack.storage.createClient({ +export const swiftClient = openstack.storage.createClient({ provider: OS.provider, keystoneAuthVersion: 'v' + OS.identityApiVersion, username: OS.username, @@ -10,5 +10,3 @@ var swiftClient = openstack.storage.createClient({ domainName: OS.domainName, region: OS.region }); - -module.exports = swiftClient; diff --git a/BackEnd/src/configs/api_code.ts b/BackEnd/src/configs/api_code.ts new file mode 100644 index 0000000..7c9425d --- /dev/null +++ b/BackEnd/src/configs/api_code.ts @@ -0,0 +1,8 @@ +const api_code = { + ok: 204, + error: 422, + forbidden: 401, + not_found: 404, +}; + +export default api_code; diff --git a/BackEnd/configs/default_index.json b/BackEnd/src/configs/default_index.json similarity index 100% rename from BackEnd/configs/default_index.json rename to BackEnd/src/configs/default_index.json diff --git a/BackEnd/src/configs/index.ts b/BackEnd/src/configs/index.ts new file mode 100644 index 0000000..e2d4eba --- /dev/null +++ b/BackEnd/src/configs/index.ts @@ -0,0 +1,2 @@ +export const secret = + process.env.NODE_ENV === 'production' ? process.env.SECRET : 'secret'; diff --git a/BackEnd/configs/log_message.js b/BackEnd/src/configs/log_message.ts similarity index 96% rename from BackEnd/configs/log_message.js rename to BackEnd/src/configs/log_message.ts index e110052..6064861 100644 --- a/BackEnd/configs/log_message.js +++ b/BackEnd/src/configs/log_message.ts @@ -1,4 +1,4 @@ -var log_message = { +const log_message = { server_access_forbidden: 'user unauthorized to access the server, his is trying to access a not owned server', server_update_ok: 'server information updated', @@ -22,4 +22,4 @@ var log_message = { }; -module.exports = log_message; +export default log_message; diff --git a/BackEnd/configs/os.js b/BackEnd/src/configs/os.ts similarity index 86% rename from BackEnd/configs/os.js rename to BackEnd/src/configs/os.ts index fbcdf92..2a0030b 100644 --- a/BackEnd/configs/os.js +++ b/BackEnd/src/configs/os.ts @@ -1,5 +1,5 @@ // rename this file OS.js -// var OS = { +// const OS = { // provider: '', // identityApiVersion: '', // username: '', @@ -11,4 +11,4 @@ // defaultContainerName: '' // }; -// module.exports = OS; +// export default OS; diff --git a/BackEnd/configs/passport.js b/BackEnd/src/configs/passport.ts similarity index 79% rename from BackEnd/configs/passport.js rename to BackEnd/src/configs/passport.ts index abe0ce2..e493673 100644 --- a/BackEnd/configs/passport.js +++ b/BackEnd/src/configs/passport.ts @@ -6,8 +6,8 @@ var User = mongoose.model('User'); passport.use(new LocalStrategy({ usernameField: 'user[email]', passwordField: 'user[password]' -}, function(email, password, done) { - User.findOne({email: email}).then(function(user){ +}, function(email : any, password : any, done : any) { + User.findOne({email: email}).then(function(user : any){ if(!user || !user.validPassword(password)){ return done(null, false, {errors: {'email or password': 'is invalid'}}); } @@ -15,4 +15,3 @@ passport.use(new LocalStrategy({ return done(null, user); }).catch(done); })); - diff --git a/BackEnd/lib/errors.js b/BackEnd/src/lib/errors.ts similarity index 86% rename from BackEnd/lib/errors.js rename to BackEnd/src/lib/errors.ts index ed460b8..6700e1a 100644 --- a/BackEnd/lib/errors.js +++ b/BackEnd/src/lib/errors.ts @@ -1,6 +1,6 @@ -var errors = { +export default { - wget_error: function (code) { + wget_error: function (code : number) { var message = ''; switch (code) { case 4: @@ -22,7 +22,7 @@ var errors = { return message; }, - group_duplicate: function (files) { + group_duplicate: function (files : any) { for (let i = 0; i < files.length - 1; i++) { for (let j = i + 1; j < files.length; j++) { if (files[i][0] === files[j][0]) { @@ -38,7 +38,7 @@ var errors = { }, - wrap_error: function (fun, status, err) { + wrap_error: function (fun : any, status : any, err : any) { if (err.fun === undefined) { throw { fun, status, err }; } else { @@ -46,7 +46,7 @@ var errors = { } }, - unwrap_error: function (res, err) { + unwrap_error: function (res : any, err : any) { if (err.fun !== undefined) { console.log('Error ' + err.fun + ': '); console.log(err.err); @@ -56,5 +56,3 @@ var errors = { } } }; - -module.exports = errors; diff --git a/BackEnd/lib/global_functions.js b/BackEnd/src/lib/global_functions.ts similarity index 59% rename from BackEnd/lib/global_functions.js rename to BackEnd/src/lib/global_functions.ts index 98248e4..7708167 100644 --- a/BackEnd/lib/global_functions.js +++ b/BackEnd/src/lib/global_functions.ts @@ -1,4 +1,4 @@ -const tokenObj = { +export const tokenObj = { regexps: [ 'Initial teacher token created: ', 'Found the following teacher tokens:\n - ', @@ -7,7 +7,7 @@ const tokenObj = { errorNotFound: 'Token not found', }; -function _asyncFunction(item, cb) { +export function asyncFunction(item : any, cb : Function) { setTimeout(() => { console.log('done with', item); cb(); @@ -18,40 +18,32 @@ function _asyncFunction(item, cb) { * create a Promise that wait before returning result * callback must be a function that take no arguments (only unit) */ -async function _timedRun(callback, ms) { +export async function timedRun(callback : Function, ms : number) { let result = await new Promise(resolve => { setTimeout(() => resolve(callback()), ms); }); return result; } -async function _tryFindTeacherToken(log, regexp, regexpLen) { +async function tryFindTeacherToken(log : string, + regexp : string, regexpLen : number) { var index = log.indexOf(regexp); if (index === -1) throw tokenObj.errorNotFound; return log.substr(index + regexpLen, tokenObj.length); } -async function _tryAllFindTeacherToken(log) { - async function _tryFindIter(regexps) { +export async function tryAllFindTeacherToken(log : any) { + async function tryFindIter(regexps : string[]) : Promise { let regexp = regexps[0]; - return _tryFindTeacherToken(log, regexp, regexp.length) + return tryFindTeacherToken(log, regexp, regexp.length) .catch(err => { if (err === tokenObj.errorNotFound && regexps.length > 1) - return _tryFindIter(regexps.slice(1)); + return tryFindIter(regexps.slice(1)); else throw err; }); } - return _tryFindIter(tokenObj.regexps); + return tryFindIter(tokenObj.regexps); } - -var global_functions = { - tokenObj, - asyncFunction: _asyncFunction, - tryFindTeacherToken: _tryAllFindTeacherToken, - timedRun: _timedRun -}; - -module.exports = global_functions; diff --git a/BackEnd/lib/log_functions.js b/BackEnd/src/lib/log_functions.ts similarity index 51% rename from BackEnd/lib/log_functions.js rename to BackEnd/src/lib/log_functions.ts index 923de8e..4a1dc5b 100644 --- a/BackEnd/lib/log_functions.js +++ b/BackEnd/src/lib/log_functions.ts @@ -1,14 +1,14 @@ -var mongoose = require('mongoose'); +import mongoose from 'mongoose' var Log = mongoose.model('Log'); -function _create(type, action, message = null, author = null, server = null) { +export function create(type : any, action : any, message : any = null, author : any = null, server : any = null) { return new Promise((resolve, reject) => { var log = new Log(); - log.type = type; - log.action = action; - log.message = message; - log.author = author; - log.server = server; + (log as any).type = type; + (log as any).action = action; + (log as any).message = message; + (log as any).author = author; + (log as any).server = server; return log.save().then(() => { console.log(log); return resolve(log); @@ -19,21 +19,13 @@ function _create(type, action, message = null, author = null, server = null) { }); } -function _delete(log) { +export function remove(log : any) { return new Promise((resolve, reject) => { - log.remove().then(() => { - return resolve(); - }, (err) => { + log.remove() + .then(resolve) + .catch((err : Error) => { console.log('Error deleting log !: ' + err); return reject(err); }); }); - } - -var log_functions = { - create: _create, - delete: _delete, -} - -module.exports = log_functions; diff --git a/BackEnd/src/lib/server_functions.ts b/BackEnd/src/lib/server_functions.ts new file mode 100644 index 0000000..63a3085 --- /dev/null +++ b/BackEnd/src/lib/server_functions.ts @@ -0,0 +1,382 @@ +import * as k8s from '@kubernetes/client-node'; +const kc = new k8s.KubeConfig(); +kc.loadFromDefault(); +const k8sApiDeploy = kc.makeApiClient(k8s.AppsV1Api); +const k8sApi = kc.makeApiClient(k8s.CoreV1Api); +const k8sApiIngress = kc.makeApiClient(k8s.ExtensionsV1beta1Api); + +k8sApiIngress.defaultHeaders = { + 'Content-Type': 'application/strategic-merge-patch+json', + ...k8sApiIngress.defaultHeaders, +}; +import { swiftClient } from '../clients/swiftClient'; +import { OS } from '../configs/OS'; + +import * as global_functions from './global_functions'; +import * as upload_functions from './upload_functions'; + +const podLabelPrefix = 'app='; +const intervalTime = 5000; + +export async function createNamespacedDeployment(deployment : any, + namespace : string) { + return k8sApiDeploy.createNamespacedDeployment(namespace, deployment); +} + +export async function readNamespacedDeployment(slug : string, + namespace : string) { + return k8sApiDeploy.readNamespacedDeployment(slug, namespace); +}; + +/** + * Return a promise with the list of pods found + * an empty list mean no pods found + */ +export async function listNamespacedPod(slug : string, namespace : string) { + return k8sApi.listNamespacedPod(namespace, undefined, undefined, undefined, + undefined, podLabelPrefix + slug) + .then(res => res.body.items); +} + +/** + * Find the first pod in the list of pods found + * if the list is empty, return an rejected promise + */ +export async function readNamespacedPod(slug : string, namespace : string) { + return listNamespacedPod(slug, namespace) + .then((items : k8s.V1Pod[]) => { + if (items.length < 1) + throw new Error('Pod not found'); + return items[0]; + }); +} + +export async function readNamespacedPodLog(slug : string, namespace : string) { + return readNamespacedPod(slug, namespace) + .then(pod => pod.metadata!.name!) + .then(name => k8sApi.readNamespacedPodLog(name, namespace)) + .then(res => res.body); +} + +export async function tryGetTeacherToken(slug : string, namespace : string) { + return readNamespacedPodLog(slug, namespace) + .then(log => global_functions.tryAllFindTeacherToken(log)); +} + +export async function catchTeacherToken(slug : string, namespace : string) { + async function watchCatchTeacherToken() { + let timedWatchCatch = + () => global_functions.timedRun(watchCatchTeacherToken, intervalTime); + + return tryGetTeacherToken(slug, namespace) + .catch(err => { + if (err === global_functions.tokenObj.errorNotFound) { + console.log("Token not found, retrying..."); + return timedWatchCatch(); + } else { + throw err; + } + }); + } + + return watchCatchTeacherToken(); +} + +export async function createNamespacedService(service : any, + namespace : string) { + return k8sApi.createNamespacedService(namespace, service); +}; + +async function patchNamespacedIngress(spec : any, namespace : string) { + return k8sApiIngress.patchNamespacedIngress('learn-ocaml', namespace, + { spec }); +}; + +export async function createNamespacedIngress(rule : any, namespace : string) { + return new Promise(function (resolve, reject) { + k8sApiIngress.readNamespacedIngress('learn-ocaml', namespace, 'true') + .then((response) => { + const spec = response.body!.spec!; + spec.rules!.push(rule); + return resolve(patchNamespacedIngress(spec, namespace)); + }) + .catch((err) => { + console.log('Error!: ' + JSON.stringify(err)); + return reject(err); + }); + }); +}; + +function createObjectDeployment(slug : string) { + return { + apiVersion: 'apps/v1', + kind: 'Deployment', + metadata: { + name: slug, + labels: { + app: slug + } + }, + spec: { + replicas: 1, + selector: { + matchLabels: { + app: slug + } + }, + template: { + metadata: { + labels: { + app: slug + } + }, + spec: { + containers: [{ + name: 'learn-ocaml', + image: 'ocamlsf/learnocaml-essok-dockerfile:latest', + ports: [{ + containerPort: 8080 + }], + env: [{ + name: 'OS_AUTH_URL', + value: OS.authUrl + }, + { + name: 'ST_AUTH_VERION', + value: OS.identityApiVersion + }, + { + name: 'OS_USERNAME', + value: OS.username + }, + { + name: 'OS_USER_DOMAIN_NAME', + value: OS.domainName + }, + { + name: 'OS_PASSWORD', + value: OS.password + }, + { + name: 'OS_PROJECT_NAME', + value: OS.projectName + }, + { + name: 'OS_PROJECT_DOMAIN_NAME', + value: OS.domainName + }, + { + name: 'OS_REGION_NAME', + value: OS.region + } + ], + args: [slug] + }], + terminationGracePeriodSeconds: 900 + } + } + } + } +} + +function createObjectService(slug : string) { + return { + apiVersion: 'v1', + kind: 'Service', + metadata: { + name: slug, + labels: { + app: slug + } + }, + spec: { + type: 'ClusterIP', + selector: { + app: slug + }, + ports: [{ + name: 'http', + port: 80, + targetPort: 8080 + }] + } + } +} + +export function createObjectRule(slug : string, username : string) { + return { + // TODO: remove hard coded URL + host: username + '.' + slug + '.learn-ocaml.org', + http: { + paths: [{ + backend: { + serviceName: slug, + servicePort: 80 + } + }] + } + } +} + +function createObjectContainer(slug : string) { + return { + name: slug, + metadata: {} + } +} + +export async function createkubelink(slug : string, username : string, + namespace : string) { + const deployment = createObjectDeployment(slug); + const service = createObjectService(slug); + const rule = createObjectRule(slug, username); + + await createNamespacedDeployment(deployment, namespace); + await createNamespacedService(service, namespace); + await createNamespacedIngress(rule, namespace); + + console.log('kubelink created'); + return 'done'; +}; + +export function createSwiftContainer(slug : string) { + return new Promise(function (resolve, reject) { + swiftClient.createContainer(createObjectContainer(slug), + function (err : any, container : any) { + if (err) return reject(err); + return resolve(container); + }); + }); +}; + +function getSwiftContainer(slug : string) { + return new Promise(function (resolve, reject) { + swiftClient.getContainers(function (err : any, containers : any) { + if (err) return reject(err); + else { + for (let i = 0; i < containers.length; i++) { + if (containers[i].name === slug) { + return resolve(containers[i]); + } else { + if (i === containers.length - 1) { + return reject('not found'); + } + } + } + } + }); + }); +}; + +export function copySwiftContainerFile(containerSrc : any, containerDst : any, file : any) { + return new Promise((resolve, reject) => { + swiftClient.copy({ + sourceContainer: containerSrc, + destinationContainer: containerDst, + sourceFile: file, + destinationFile: file + }, (err : any, res : any) => { + if (err !== null) + reject(err); + resolve(res); + }); + }); +} + +export function copySwiftContainer(containerSrc : any, containerDst : any) { + return new Promise((resolve, reject) => { + swiftClient.getFiles(containerSrc, (err : any, files : any) => { + if (err !== null) + reject(err); + files = files.map((file : any) => copySwiftContainerFile(containerSrc, + containerDst, + file)); + Promise.all(files).then(resolve, reject); + }); + }); +} + +function destroySwiftContainer(slug : string) { + return new Promise(function (resolve, reject) { + getSwiftContainer(slug) + .then(function (response) { + swiftClient.destroyContainer(response, + function (err : any, result : any) { + if (err) return reject(err); + return resolve(result); + }); + }).catch(() => { + console.log('already deleted'); + return resolve('already deleted'); + }); + }); +}; + +function removeIngressFile(rules : any, slug : string) { + for (let index = 0; index < rules.length; index++) { + if (rules[index].http.paths[0].backend.serviceName === slug) { + rules.splice(index, 1); + return 'done'; + } else if (index === rules.length - 1) { + return 'already deleted'; + } + } +} + +export function deleteNamespacedIngress(slug : string, namespace : string) { + return k8sApiIngress.readNamespacedIngress('learn-ocaml', namespace, 'true') + .then(async (response) => { + const spec = response!.body!.spec!; + console.log('Ingress read'); + console.log('rule find : ' + spec.rules!); + removeIngressFile(spec.rules!, slug); + console.log('Ingress removed'); + await patchNamespacedIngress(spec, namespace) + .then(() => console.log('Ingress patched')); + return 'done'; + }); +}; + +async function deleteNamespacedService(slug : string, namespace : string) { + await k8sApi.readNamespacedService(slug, namespace); + return k8sApi.deleteNamespacedService(slug, namespace); +}; + +async function deleteNamespacedDeployment(slug : string, namespace : string, + waitPodDie = true) { + async function watchPodDie() { + let timedWatchRun = + () => global_functions.timedRun(watchPodDie, intervalTime); + return readNamespacedPod(slug, namespace) + .then(_ => timedWatchRun()) + .catch(_ => true); + } + + return k8sApiDeploy.deleteNamespacedDeployment(slug, namespace) + .then(_ => (waitPodDie) ? watchPodDie() : true) + .catch(_ => false); +}; + +export async function removekubelink(slug : string, namespace : string) { + await deleteNamespacedIngress(slug, namespace) + .then(() => console.log('ingress removed')) + .catch(() => console.error('ingress error, ignoring...')); + await deleteNamespacedService(slug, namespace) + .then(() => console.log('service removed')) + .catch(() => console.error('service error, ignoring...')); + await deleteNamespacedDeployment(slug, namespace) + .then(() => console.log('deployment removed')) + .catch(() => console.error('deployment error, ignoring...')); + return 'done'; +} + +export async function deleteAll(slug : string, namespace : string, + path : string) { + await removekubelink(slug, namespace) + .then(() => console.log('kubelink removed')); + await destroySwiftContainer(slug) + .then(() => console.log('swift container removed')); + await upload_functions.removeDir(path) + .then(() => console.log('server deleted')); + return 'done'; +} diff --git a/BackEnd/lib/upload_functions.js b/BackEnd/src/lib/upload_functions.ts similarity index 74% rename from BackEnd/lib/upload_functions.js rename to BackEnd/src/lib/upload_functions.ts index 3b4a41b..60885a7 100644 --- a/BackEnd/lib/upload_functions.js +++ b/BackEnd/src/lib/upload_functions.ts @@ -5,7 +5,6 @@ const url = require('url'); const child_process = require('child_process'); const rimraf = require("rimraf"); const swiftClient = require('../clients/swiftClient'); -const read = require('fs-readdir-recursive'); const global_functions = require('./global_functions'); const saveFile = 'index_saved.txt' const separator = '®'; @@ -26,13 +25,15 @@ const groupPrefix = 'group-'; const defaultIndexObj = require(defaultIndexJsonPath); +export const read = require('fs-readdir-recursive'); + /** * Workaround to convert a tabOfName (a dumb structure of matrix) * the dumb structure is like [ [ "g1", "ex1", "ex2", ...], [ "g2", "ex3", ... ] ] * to a standart list of groups * a group has a structure like { title: "g1", exercises: ["ex1", "ex2", ...] } */ -function tabOfNameToGroups(tabOfName) { +export function tabOfNameToGroups(tabOfName : string[][]) { return tabOfName.map(group => { return { title: group[0], exercises: group.slice(1) }; }); @@ -43,26 +44,26 @@ function tabOfNameToGroups(tabOfName) { * return a promise with the list of groups * a group has a structure like { title: "g1", exercises: ["ex1", "ex2", ...] } */ -async function loadIndexJson(dirPath) { +export async function loadIndexJson(dirPath : string) { const filePath = path.join(dirPath, defaultIndexJsonFilename); return fsPromises.readFile(filePath) - .then(buffer => JSON.parse(buffer)) - .then(indexObject => Object.values(indexObject.groups)); + .then((buffer : string) => JSON.parse(buffer)) + .then((indexObject : any) => Object.values(indexObject.groups)); } /** * Save the index.json from a list of groups object * a group has a structure like { title: "g1", exercises: ["ex1", "ex2", ...] } */ -async function saveIndexJson(dirPath, groups) { +export async function saveIndexJson(dirPath : string, groups : any) { const indexObject = Object.assign({}, defaultIndexObj); const filePath = path.join(dirPath, defaultIndexJsonFilename); for (let i = 0; i < groups.length; i++) { indexObject.groups[groupPrefix + i] = groups[i]; } - return Promise.resolve(JSON.stringify(indexObject, null, 2)) + return Promise.resolve(JSON.stringify(indexObject, null, 4)) .then(buffer => fsPromises.writeFile(filePath, buffer)); } @@ -72,8 +73,8 @@ function create_IndexJSON_header() { }); } -function create_IndexJSON_body(tabOfName) { - return new Promise(function (resolve, reject) { +function create_IndexJSON_body(tabOfName : any) { + return new Promise(resolve => { var body = ""; for (let i = 0; i < tabOfName.length; i++) { var group = tabOfName[i]; @@ -102,13 +103,13 @@ function create_IndexJSON_body(tabOfName) { } function create_IndexJSON_footer() { - return new Promise(function (resolve, reject) { + return new Promise(resolve => { return resolve('} }'); }); } -function addFileInTabOfName(element, tmp) { - return new Promise(function (resolve, reject) { +function addFileInTabOfName(element : any, tmp : any) { + return new Promise(resolve => { var new_group = []; for (let i = 0; i < element.length; i++) { if (i === 0) { @@ -129,15 +130,16 @@ function addFileInTabOfName(element, tmp) { }); } -function file_to_delete(path, element, useless, tabOfName) { +function file_to_delete(path : string, element : any, + useless : any, tabOfName : any) { return new Promise(function (resolve, reject) { - fs.stat(path + element, function (err, stat) { + fs.stat(path + element, function (err : any, stat : any) { if (err) return reject(err); if (stat.isFile()) { console.log(path + element + ' is a file, so it will be deleted'); - fs.unlink(path + element, function (err) { + fs.unlink(path + element, function (err : any) { if (err) return reject(err); - return resolve(); + return resolve(undefined); }); } else if (stat.isDirectory()) { @@ -157,7 +159,7 @@ function file_to_delete(path, element, useless, tabOfName) { const group = tabOfName[i]; if (group.includes(element)) { console.log(path + element + ' is included in tabOfName file, possess an meta.json file and is not included in useless file, so it will be kept'); - return resolve(); + return resolve(undefined); } else { if (i === tabOfName.length - 1) { @@ -179,23 +181,23 @@ function file_to_delete(path, element, useless, tabOfName) { }); } -function deleteDir(tab_of_dir) { +function deleteDir(tab_of_dir : any) { return new Promise(function (resolve, reject) { var tmp = tab_of_dir.length; console.log('tmp.length : ' + tmp); if (tmp === 0) { console.log('no more file to delete'); - return resolve(); + return resolve(undefined); } for (let i = 0; i < tab_of_dir.length; i++) { - rimraf(tab_of_dir[i], function (err) { + rimraf(tab_of_dir[i], function (err : any) { if (err) return reject(err); console.log('file deleted in tmp'); tmp--; console.log('tmp.length : ' + tmp); if (tmp === 0) { console.log('no more file to delete'); - return resolve(); + return resolve(undefined); } }) } @@ -208,8 +210,11 @@ function deleteDir(tab_of_dir) { * @param {*} format * @param {*} archive_name */ -async function createArchiveFromDirectory(source, dest, format, archive_name) { - var files = read(source).map(file => [path.join(source, file), path.join(dest, file)]); +export async function createArchiveFromDirectory(source : string, dest : string, + format : any, archive_name : any) { + var files = read(source) + .map((file : string) => + [path.join(source, file), path.join(dest, file)]); if (files === []) { throw 'empty files list'; } @@ -223,42 +228,43 @@ async function createArchiveFromDirectory(source, dest, format, archive_name) { * format : format of compression (ex: 'zip') * archive_name : the name of the archive */ -async function createArchive(files, format, archive_name = 'archive') { +export async function createArchive(files : any, format : any, + archive_name = 'archive') { const stream = fs.createWriteStream(archive_name + '.' + format); const archive = archiver(format, {}); await new Promise(resolve => { stream.on('close', function () { console.log('archive ' + archive + ' created'); - resolve(); + resolve(undefined); }); archive.pipe(stream); - files.forEach(file => { + files.forEach((file : any) => { archive.file(file[0], { name: file[1] }); }); archive.finalize(); }); } -function _desarchived(dest_path, source_path) { +export function desarchived(dest_path : any, source_path : any) { return new Promise(function (resolve, reject) { fs.createReadStream(source_path).pipe(unzipper.Extract({ path: dest_path })) - .on('close', function (err) { + .on('close', function (err : any) { if (err) return reject(err); return resolve(dest_path); }) - .on('error', function (err) { + .on('error', function (err : any) { return reject(err); }); }); } -function _checkFiles(path) { +export function checkFiles(path : string) { return new Promise(function (resolve, reject) { if (fs.existsSync(path)) { - fs.readdir(path, function (err, files) { + fs.readdir(path, function (err : any, files : any) { if (err) return reject(err); else if (!files.length) { return resolve([]); @@ -271,16 +277,14 @@ function _checkFiles(path) { }); } -function _fileExists(path) { - return new Promise(function (resolve, reject) { - return resolve(fs.existsSync(path)); - }) +export function fileExists(path : string) { + return Promise.resolve(fs.existsSync(path)); } -function _unlinkSync(path) { +export function unlinkSync(path : string) { return new Promise(function (resolve, reject) { if (fs.existsSync(path)) { - fs.unlink(path, function (err) { + fs.unlink(path, function (err : any) { if (err) return reject(err); return resolve('deleted'); }) @@ -290,13 +294,13 @@ function _unlinkSync(path) { }); } -function _copyFile(source, dest) { +export function copyFile(source : any, dest : any) { return new Promise(function (resolve, reject) { if (fs.existsSync(source)) { - fs.copyFile(source, dest, (err) => { + fs.copyFile(source, dest, (err : any) => { if (err) return reject(err); console.log(source + 'was copied to ' + dest); - return resolve(); + return resolve(undefined); }); } else { return reject('Source file doesnt exist'); @@ -304,33 +308,35 @@ function _copyFile(source, dest) { }) } -function _download_from_url(file_url, dest_path) { +export function download_from_url(file_url : any, dest_path : any) { return new Promise(function (resolve, reject) { var file_name = url.parse(file_url).pathname.split('/').pop(); var wget = 'wget -P ' + dest_path + ' ' + file_url; - child_process.exec(wget, function (err, stdout, stderr) { + child_process.exec(wget, (err : any) => { if (err) return reject(err); return resolve(dest_path + file_name); }); }); } -function _delete_useless_files(useless, path, tabOfName, files) { +export function delete_useless_files(useless : any, path : any, + tabOfName : any, files : any) { return new Promise(function (resolve, reject) { if (useless === [] || useless === undefined || useless === null) { return resolve('nothing to delete'); } //console.log('tabOfName before filter : ' + tabOfName); - tabOfName = tabOfName.filter(group => group.length >= 2); + tabOfName = tabOfName.filter((group : any) => group.length >= 2); //console.log('tabOfName after filter : ' + tabOfName); - var tmp = []; + var tmp : any = []; var itemsProcessed = 0; - files.forEach((element, index, array) => { + files.forEach((element : any, index : any, array : any) => { global_functions.asyncFunction(element, () => { - file_to_delete(path, element, useless, tabOfName).then((response) => { + file_to_delete(path, element, useless, tabOfName) + .then((response) => { if (response) { console.log(response + ' added in tmp'); tmp.push(response); @@ -356,14 +362,14 @@ function _delete_useless_files(useless, path, tabOfName, files) { }); } -function _create_new_tabOfName(save_path, path, tabOfName) { +export function create_new_tabOfName(save_path : any, path : any, tabOfName : any) { return new Promise(function (resolve, reject) { var nameProcessed = 0; var tmp = fs.readdirSync(path); - var new_tabOfName = [[]]; + var new_tabOfName : any = [[]]; - tabOfName.forEach((element, index, array) => { + tabOfName.forEach((element : any, index : any, array : any) => { global_functions.asyncFunction(element, () => { addFileInTabOfName(element, tmp).then(async (response) => { if (response) { @@ -374,7 +380,7 @@ function _create_new_tabOfName(save_path, path, tabOfName) { nameProcessed++; if (nameProcessed === array.length) { //console.log('new_tabOfName before filter : ' + new_tabOfName); - new_tabOfName = new_tabOfName.filter(group => group.length >= 2); + new_tabOfName = new_tabOfName.filter((group : any) => group.length >= 2); //console.log('new_tabOfName after filter : ' + new_tabOfName); if (!new_tabOfName.length) { return reject(': No correct files found for index.json'); @@ -395,16 +401,16 @@ function _create_new_tabOfName(save_path, path, tabOfName) { }); } -function _save_tabOfName(save_path, tabOfName) { +function _save_tabOfName(save_path : any, tabOfName : any) { return new Promise(function (resolve, reject) { var line = ''; - tabOfName.forEach(tab => { - tab.forEach(element => { + tabOfName.forEach((tab : any) => { + tab.forEach((element : any) => { line += element + separator; }); line += '\n'; }); - fs.writeFile(save_path + saveFile, line, function (err) { + fs.writeFile(save_path + saveFile, line, function (err : any) { if (err) { console.log('error in saving tabofname'); return reject(err); @@ -415,9 +421,9 @@ function _save_tabOfName(save_path, tabOfName) { }) } -function _load_tabOfName(save_path) { +export function load_tabOfName(save_path : any) { return new Promise(function (resolve, reject) { - fs.readFile(save_path + saveFile, 'utf8', function (err, data) { + fs.readFile(save_path + saveFile, 'utf8', (err : any, data : any) => { if (err) { if (err.code === 'ENOENT') { console.error('The save file doesnt exist now, it is the first time the repository is created'); @@ -449,15 +455,15 @@ function _load_tabOfName(save_path) { }) } -function _create_indexJSON(path, tabOfName) { +export function create_indexJSON(path : any, tabOfName : any) { return new Promise(function (resolve, reject) { - create_IndexJSON_header().then((header) => { + create_IndexJSON_header().then((header : any) => { //console.log('header created : \n' + header); - create_IndexJSON_body(tabOfName).then((body) => { + create_IndexJSON_body(tabOfName).then((body : any) => { //console.log('body created : \n' + body); - create_IndexJSON_footer().then((footer) => { + create_IndexJSON_footer().then((footer : any) => { //console.log('footer created : \n' + footer); - fs.writeFile(path, header + body + footer, function (err) { + fs.writeFile(path, header + body + footer, (err : any) => { if (err) return reject(err); console.log('index.json : ' + header + body + footer); return resolve(path + 'exercises/index.json'); @@ -468,7 +474,7 @@ function _create_indexJSON(path, tabOfName) { }); } -async function _getFromSwift(path, slug, target) { +export async function getFromSwift(path : any, slug : any, target : any) { let openrc = 'cd ~ && source openrc.sh'; let swift = 'swift download ' + slug + ' -D ' + path @@ -483,13 +489,13 @@ async function _getFromSwift(path, slug, target) { return exec(cmd, { shell: '/bin/bash', maxBuffer: 1024 * 4096 }) .then(() => 'done') - .catch((err) => { + .catch((err : any) => { console.log('Error exec !: ' + err); throw err; }); } -async function _sendToSwift(path, slug, remote) { +export async function sendToSwift(path : any, slug : any, remote : any) { let openrc = 'cd ~ && source openrc.sh'; let swift = 'swift upload ' + slug + ' ' + path @@ -502,16 +508,16 @@ async function _sendToSwift(path, slug, remote) { let cmd = openrc + ' && ' + swift; return exec(cmd, { shell: '/bin/bash', maxBuffer: 1024 * 4096 }) .then(() => 'done') - .catch((err) => { + .catch((err : any) => { console.log('Error exec !: ' + err); throw err; }); } -function _removeDir(path) { +export function removeDir(path : any) { return new Promise(function (resolve, reject) { if (fs.existsSync(path)) { - rimraf(path, function (err) { + rimraf(path, function (err : any) { if (err) return reject(err); return resolve('removed'); }); @@ -520,20 +526,21 @@ function _removeDir(path) { }); } -function _renameDir(oldPath, newPath, unknown, remove_if_not_empty) { +export function renameDir(oldPath : any, newPath : any, + unknown : any, remove_if_not_empty : any) { return new Promise(function (resolve, reject) { if (unknown) { - fs.readdir(oldPath, function (err, files) { + fs.readdir(oldPath, function (err : any, files : any) { if (err) return reject(err); else { - fs.rename(oldPath + files[0], newPath, function (err) { + fs.rename(oldPath + files[0], newPath, (err : any) => { if (err) return reject(err); return resolve('renamed'); }) } }) } else { - fs.rename(oldPath, newPath, function (err) { + fs.rename(oldPath, newPath, function (err : any) { if (err) { return reject(err); } @@ -544,23 +551,9 @@ function _renameDir(oldPath, newPath, unknown, remove_if_not_empty) { }) } -function _moveDir(oldPath, newPath) { - return new Promise(function (resolve, reject) { - fsDir.move(oldPath, newPath, function (err) { - if (err) { - return reject(err); - } - else { - return resolve('ok'); - } - }) - - }) -} - -function _createDir(path) { +export function createDir(path : any) { return new Promise(function (resolve, reject) { - fs.mkdir(path, function (err) { + fs.mkdir(path, function (err : any) { if (err) { if (err.code === 'EEXIST') { console.error('my repository already exists at ' + path); @@ -573,14 +566,16 @@ function _createDir(path) { }); } -function _createArbo(path, server_name, safe_folder, dirt_folder, save_folder, download_folder) { +export function createArbo(path : any, server_name : any, + safe_folder : any, dirt_folder : any, save_folder : any, + download_folder : any) { return new Promise(function (resolve, reject) { - _createDir(path).then(() => { - _createDir(path + server_name).then(() => { - _createDir(path + server_name + safe_folder).then(() => { - _createDir(path + server_name + dirt_folder).then(() => { - _createDir(path + server_name + save_folder).then(() => { - _createDir(path + server_name + download_folder).then(() => { + createDir(path).then(() => { + createDir(path + server_name).then(() => { + createDir(path + server_name + safe_folder).then(() => { + createDir(path + server_name + dirt_folder).then(() => { + createDir(path + server_name + save_folder).then(() => { + createDir(path + server_name + download_folder).then(() => { return resolve('done'); }, (err) => { console.log('Error creating download_folder !: ' + err); @@ -610,9 +605,9 @@ function _createArbo(path, server_name, safe_folder, dirt_folder, save_folder, d }); } -function _copyDir(source, destination) { +export function copyDir(source : any, destination : any) { return new Promise(function (resolve, reject) { - fsDir.copy(source, destination, function (err) { + fsDir.copy(source, destination, (err : any) => { if (err) { console.log('An error occured while copying the folder.') return reject(err); @@ -623,9 +618,9 @@ function _copyDir(source, destination) { }) } -function _moveDir(source, destination) { +export function moveDir(source : any, destination : any) { return new Promise(function (resolve, reject) { - fsDir.move(source, destination, function (err) { + fsDir.move(source, destination, function (err : any) { if (err) { console.log('An error occured while moving the folder.') return reject(err); @@ -637,19 +632,22 @@ function _moveDir(source, destination) { } -function _archive_traitement(dest_path, source_path, archive_folder, safe_folder, link_github = '') { +export function archive_traitement(dest_path : any, source_path : any, + archive_folder : any, safe_folder : any, + link_github = '') { return new Promise(function (resolve, reject) { - _desarchived(dest_path + archive_folder, source_path).then((response) => { + desarchived(dest_path + archive_folder, source_path).then((response) => { console.log('desachived done'); - _checkFiles(dest_path + archive_folder).then((archive_name) => { + checkFiles(dest_path + archive_folder).then((archive_name : any) => { console.log('check done'); - _copyDir(dest_path + archive_folder + archive_name[0] + link_github, dest_path + safe_folder).then((response) => { + copyDir(dest_path + archive_folder + archive_name[0] + link_github, dest_path + safe_folder) + .then((response : any) => { console.log('copyDir done'); - _removeDir(dest_path + archive_folder).then(() => { + removeDir(dest_path + archive_folder).then(() => { console.log('removeDir done'); - _unlinkSync(source_path).then((response) => { + unlinkSync(source_path).then((response) => { console.log('unlink done'); - _checkFiles(dest_path + safe_folder).then((files) => { + checkFiles(dest_path + safe_folder).then((files) => { console.log('checkFiles done'); console.log('archive traitement done'); return resolve(files); @@ -679,28 +677,31 @@ function _archive_traitement(dest_path, source_path, archive_folder, safe_folder }); }); } -function _archive_complete_traitement(dest_path, safe_folder, slug) { + +export function archive_complete_traitement(dest_path : any, safe_folder : any, + slug : any) { return new Promise(function (resolve, reject) { var fileProcessed = 0; - _checkFiles(dest_path + safe_folder + repository).then((files) => { + checkFiles(dest_path + safe_folder + repository) + .then((files : any) => { console.log('checkFiles done'); if (files === undefined || files === [] || files.length === 0) { return reject('no correct repository found, please update an archive with the correct format : repository + sync'); } else { - files.forEach((element, index, array) => { + files.forEach((element : any, index : any, array : any) => { global_functions.asyncFunction(element, () => { - _copyDir(dest_path + safe_folder + repository + '/' + element, dest_path + safe_folder + element).then((response) => { + copyDir(dest_path + safe_folder + repository + '/' + element, dest_path + safe_folder + element).then((response : any) => { console.log('copyDir ' + fileProcessed + ' done'); fileProcessed++; if (fileProcessed === array.length) { console.log('checkFiles done'); // return resolve('ok'); - _sendToSwift(dest_path + safe_folder + repository, slug, repository).then(() => { + sendToSwift(dest_path + safe_folder + repository, slug, repository).then(() => { console.log('repository send'); - _sendToSwift(dest_path + safe_folder + sync, slug, sync).then(() => { + sendToSwift(dest_path + safe_folder + sync, slug, sync).then(() => { console.log('sync send'); - _removeDir(dest_path + safe_folder + repository).then(() => { - _removeDir(dest_path + safe_folder + sync).then(() => { + removeDir(dest_path + safe_folder + repository).then(() => { + removeDir(dest_path + safe_folder + sync).then(() => { return resolve('ok'); }, (err) => { console.log('Error removeDir sync !: ' + err); @@ -734,31 +735,33 @@ function _archive_complete_traitement(dest_path, safe_folder, slug) { }) } +export function parse_url(file_url : any) { + return url.parse(file_url).host; +} + +/* var upload_functions = { - read, - desarchived: _desarchived, - checkFiles: _checkFiles, - unlinkSync: _unlinkSync, - download_from_url: _download_from_url, - delete_useless_files: _delete_useless_files, - create_new_tabOfName: _create_new_tabOfName, - create_indexJSON: _create_indexJSON, - sendToSwift: _sendToSwift, - getFromSwift: _getFromSwift, + unlinkSync: unlinkSync, + download_from_url: download_from_url, + delete_useless_files: delete_useless_files, + create_new_tabOfName: create_new_tabOfName, + create_indexJSON: create_indexJSON, + sendToSwift: sendToSwift, + getFromSwift: getFromSwift, createArchive, createArchiveFromDirectory, - removeDir: _removeDir, - renameDir: _renameDir, - createArbo: _createArbo, - copyFile: _copyFile, - copyDir: _copyDir, - moveDir: _moveDir, - fileExists: _fileExists, - load_tabOfName: _load_tabOfName, - archive_traitement: _archive_traitement, - archive_complete_traitement: _archive_complete_traitement, - createDir: _createDir, - parse_url: function (file_url) { + removeDir: removeDir, + renameDir: renameDir, + createArbo: createArbo, + copyFile: copyFile, + copyDir: copyDir, + moveDir: moveDir, + fileExists: fileExists, + load_tabOfName: load_tabOfName, + archive_traitement: archive_traitement, + archive_complete_traitement: archive_complete_traitement, + createDir: createDir, + parse_url: function (file_url : any) { return url.parse(file_url).host; }, saveIndexJson, @@ -767,3 +770,4 @@ var upload_functions = { }; module.exports = upload_functions; +*/ diff --git a/BackEnd/lib/user_functions.js b/BackEnd/src/lib/user_functions.ts similarity index 51% rename from BackEnd/lib/user_functions.js rename to BackEnd/src/lib/user_functions.ts index e99f207..60bb8bb 100644 --- a/BackEnd/lib/user_functions.js +++ b/BackEnd/src/lib/user_functions.ts @@ -1,20 +1,20 @@ -const k8s = require('@kubernetes/client-node'); +import * as k8s from '@kubernetes/client-node'; const kc = new k8s.KubeConfig(); kc.loadFromDefault(); const k8sApi = kc.makeApiClient(k8s.CoreV1Api); -function _createNamespace(namespace) { - return k8sApi.createNamespace(namespace); +function _createNamespace(namespace : k8s.V1Namespace) { + return k8sApi.createNamespace(namespace); }; -function _readNamespace(namespace) { - return k8sApi.readNamespace(namespace); +function _readNamespace(namespace : string) { + return k8sApi.readNamespace(namespace); }; -function _createObjectNamespace(_name) { - return namespace = { +function _createObjectNamespace(name : any) { + return { metadata: { - name: _name, + name, }, }; } diff --git a/BackEnd/models/Log.js b/BackEnd/src/models/Log.ts similarity index 92% rename from BackEnd/models/Log.js rename to BackEnd/src/models/Log.ts index 8f93a07..9062bc2 100644 --- a/BackEnd/models/Log.js +++ b/BackEnd/src/models/Log.ts @@ -9,7 +9,7 @@ var LogSchema = new mongoose.Schema({ server: { type: mongoose.Schema.Types.ObjectId, ref: 'Server' } }, { timestamps: true }); -LogSchema.methods.toJSONFor = function (user) { +LogSchema.methods.toJSONFor = function (user : any) { return { type: this.type, action: this.action, diff --git a/BackEnd/models/Server.js b/BackEnd/src/models/Server.ts similarity index 61% rename from BackEnd/models/Server.js rename to BackEnd/src/models/Server.ts index f0f0dc4..449f5c8 100644 --- a/BackEnd/models/Server.js +++ b/BackEnd/src/models/Server.ts @@ -1,4 +1,4 @@ -var mongoose = require('mongoose'); +import mongoose from 'mongoose'; var uniqueValidator = require('mongoose-unique-validator'); var slug = require('slug'); const domain = 'learn-ocaml.org'; @@ -19,31 +19,31 @@ var ServerSchema = new mongoose.Schema({ ServerSchema.plugin(uniqueValidator, { message: 'is already taken' }); ServerSchema.pre('validate', function (next) { - if (!this.slug) { - this.slugify(); + if (!(this as any).slug) { + (this as any).slugify(); } - this.url = this.author.username + '.' + this.slug + '.' + domain; + (this as any).url = (this as any).author.username + '.' + (this as any).slug + '.' + domain; next(); }); ServerSchema.methods.slugify = function () { // this.slug = slug(this.title) + '-' + (Math.random() * Math.pow(36, 6) | 0).toString(36); - this.slug = slug(this.title); + (this as any).slug = slug((this as any).title); }; ServerSchema.methods.toJSONFor = function (user) { return { - slug: this.slug, - title: this.title, - description: this.description, - body: this.body, - createdAt: this.createdAt, - updatedAt: this.updatedAt, - author: this.author.toProfileJSONFor(user), - active: this.active, - volume: this.volume, - token: this.token, - url: this.url + slug: (this as any).slug, + title: (this as any).title, + description: (this as any).description, + body: (this as any).body, + createdAt: (this as any).createdAt, + updatedAt: (this as any).updatedAt, + author: (this as any).author.toProfileJSONFor(user), + active: (this as any).active, + volume: (this as any).volume, + token: (this as any).token, + url: (this as any).url }; }; diff --git a/BackEnd/models/User.js b/BackEnd/src/models/User.ts similarity index 60% rename from BackEnd/models/User.js rename to BackEnd/src/models/User.ts index f5f2001..7e50fe7 100644 --- a/BackEnd/models/User.js +++ b/BackEnd/src/models/User.ts @@ -1,12 +1,26 @@ -var mongoose = require('mongoose'); +import mongoose from 'mongoose'; var uniqueValidator = require('mongoose-unique-validator'); var crypto = require('crypto'); var jwt = require('jsonwebtoken'); var secret = require('../configs').secret; var UserSchema = new mongoose.Schema({ - username: { type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/^[a-zA-Z0-9]+$/, 'is invalid'], index: true }, - email: { type: String, lowercase: true, unique: true, required: [true, "can't be blank"], match: [/\S+@\S+\.\S+/, 'is invalid'], index: true }, + username: { + type: String, + lowercase: true, + unique: true, + required: [true, "can't be blank"], + match: [/^[a-zA-Z0-9]+$/, 'is invalid'], + index: true + }, + email: { + type: String, + lowercase: true, + unique: true, + required: [true, "can't be blank"], + match: [/\S+@\S+\.\S+/, 'is invalid'], + index: true + }, description: String, place: String, goal: String, @@ -22,13 +36,13 @@ var UserSchema = new mongoose.Schema({ UserSchema.plugin(uniqueValidator, { message: 'is already taken.' }); UserSchema.methods.validPassword = function(password) { - var hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); - return this.hash === hash; + var hash = crypto.pbkdf2Sync(password, (this as any).salt, 10000, 512, 'sha512').toString('hex'); + return (this as any).hash === hash; }; UserSchema.methods.setPassword = function(password) { - this.salt = crypto.randomBytes(16).toString('hex'); - this.hash = crypto.pbkdf2Sync(password, this.salt, 10000, 512, 'sha512').toString('hex'); + (this as any).salt = crypto.randomBytes(16).toString('hex'); + (this as any).hash = crypto.pbkdf2Sync(password, (this as any).salt, 10000, 512, 'sha512').toString('hex'); }; UserSchema.methods.generateJWT = function() { @@ -38,20 +52,20 @@ UserSchema.methods.generateJWT = function() { return jwt.sign({ id: this._id, - username: this.username, - exp: parseInt(exp.getTime() / 1000), + username: (this as any).username, + exp: (exp.getTime() / 1000), }, secret); }; UserSchema.methods.isAdmin = function() { - return this.admin; + return (this as any).admin; }; UserSchema.methods.startProcessing = function() { var user = this; return new Promise(function(resolve, reject) { - user.processing = true; - if (user.processing === true) { + (user as any).processing = true; + if ((user as any).processing === true) { user.save().then(() => { return resolve(true); }) @@ -62,8 +76,8 @@ UserSchema.methods.startProcessing = function() { UserSchema.methods.endProcessing = function() { var user = this; return new Promise(function(resolve, reject) { - user.processing = false; - if (user.processing === false) { + (user as any).processing = false; + if ((user as any).processing === false) { user.save().then(() => { return resolve(true); }) @@ -73,7 +87,7 @@ UserSchema.methods.endProcessing = function() { UserSchema.methods.findAllUsers = function(query, limit, offset) { - if (this.isAdmin()) { + if ((this as any).isAdmin()) { return Promise.all([ mongoose.model('User').find(query) @@ -87,7 +101,7 @@ UserSchema.methods.findAllUsers = function(query, limit, offset) { }; UserSchema.methods.findAllLogs = function(query, limit, offset) { - if (this.isAdmin()) { + if ((this as any).isAdmin()) { return Promise.all([ mongoose.model('Log').find(query) @@ -119,15 +133,15 @@ UserSchema.methods.findAllServersOfAnUser = function(query_, author, payload) { offset = query_.offset; } if (typeof query_.active !== 'undefined') { - query.active = query_.active; + (query as any).active = query_.active; } - if (this.isAdmin()) { + if ((this as any).isAdmin()) { if (author) { - query.author = author._id; + (query as any).author = author._id; } } else { - query.author = payload.id; + (query as any).author = payload.id; } return Promise.all([ mongoose.model('Server').find(query) @@ -142,31 +156,31 @@ UserSchema.methods.findAllServersOfAnUser = function(query_, author, payload) { UserSchema.methods.toAuthJSON = function() { return { - username: this.username, - email: this.email, - token: this.generateJWT(), - description: this.description, - place: this.place, - goal: this.goal, - admin: this.admin, - image: this.image, - active: this.active, - processing: this.processing, - authorized: this.authorized, + username: (this as any).username, + email: (this as any).email, + token: (this as any).generateJWT(), + description: (this as any).description, + place: (this as any).place, + goal: (this as any).goal, + admin: (this as any).admin, + image: (this as any).image, + active: (this as any).active, + processing: (this as any).processing, + authorized: (this as any).authorized, }; } UserSchema.methods.toProfileJSONFor = function() { return { - email: this.email, - username: this.username, - description: this.description, - place: this.place, - goal: this.goal, - active: this.active, - authorized: this.authorized, - processing: this.processing, - image: this.image || 'https://essok.learn-ocaml.org/assets/images/default_avatar.jpg', + email: (this as any).email, + username: (this as any).username, + description: (this as any).description, + place: (this as any).place, + goal: (this as any).goal, + active: (this as any).active, + authorized: (this as any).authorized, + processing: (this as any).processing, + image: (this as any).image || 'https://essok.learn-ocaml.org/assets/images/default_avatar.jpg', }; }; diff --git a/BackEnd/src/routes/api/index.ts b/BackEnd/src/routes/api/index.ts new file mode 100644 index 0000000..bf7d69d --- /dev/null +++ b/BackEnd/src/routes/api/index.ts @@ -0,0 +1,27 @@ +import { + Request, + Response, + NextFunction, + Router, +} from 'express'; + +const router = Router(); + +router.use('/', require('./users')); +router.use('/profiles', require('./profiles')); +router.use('/servers', require('./server')); +router.use('/uploads', require('./upload')); + +router.use(function (err : any, _req : Request, + res : Response, next : NextFunction) { + if(err.name === 'ValidationError'){ + const errors : { [key : string] : any} = err.errors; + Object.keys(errors).forEach((key : string) => { + errors[key] = errors[key].message; + }); + return res.status(422).json({ errors }) + } + return next(err); +}); + +module.exports = router; diff --git a/BackEnd/routes/api/profiles.js b/BackEnd/src/routes/api/profiles.ts similarity index 68% rename from BackEnd/routes/api/profiles.js rename to BackEnd/src/routes/api/profiles.ts index 20e21a8..b0b7480 100644 --- a/BackEnd/routes/api/profiles.js +++ b/BackEnd/src/routes/api/profiles.ts @@ -1,12 +1,16 @@ -var router = require('express').Router(); +import { Router } from 'express'; var mongoose = require('mongoose'); var User = mongoose.model('User'); -var auth = require('../auth'); -const api_code = require('../../configs/api_code'); + +import auth from '../auth'; + +import api_code from '../../configs/api_code'; + +const router = Router(); // Preload user profile on routes with ':username' -router.param('username', function (req, res, next, username) { - User.findOne({ username: username }).then(function (user) { +router.param('username', function (req : any, res, next, username) { + User.findOne({ username: username }).then(function (user : any) { if (!user) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'User not found' } }); } req.profile = user; @@ -15,7 +19,7 @@ router.param('username', function (req, res, next, username) { }).catch(next); }); -router.get('/:username', auth.required, function (req, res, next) { +router.get('/:username', auth.required, function (req : any, res, next) { Promise.all([ req.payload ? User.findById(req.payload.id) : null, ]).then(function (results) { @@ -26,12 +30,11 @@ router.get('/:username', auth.required, function (req, res, next) { ) { return res.sendStatus(api_code.forbidden); } else return res.json({ profile: req.profile.toProfileJSONFor(user) }); }).catch(next); - }); // code duplication to remove in the future -router.get('/user/:username', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.get('/user/:username', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user || (!user.isAdmin() && !user.authorized) || ((user.username !== req.profile.username) && (!user.isAdmin())) diff --git a/BackEnd/routes/api/server.js b/BackEnd/src/routes/api/server.ts similarity index 86% rename from BackEnd/routes/api/server.js rename to BackEnd/src/routes/api/server.ts index b49f048..c4d8a46 100644 --- a/BackEnd/routes/api/server.js +++ b/BackEnd/src/routes/api/server.ts @@ -1,21 +1,24 @@ -var router = require('express').Router(); +import { Router } from 'express'; var mongoose = require('mongoose'); var Server = mongoose.model('Server'); var User = mongoose.model('User'); -var auth = require('../auth'); -var events = require('events'); -const server_functions = require('../../lib/server_functions'); -const log_functions = require('../../lib/log_functions'); -const errors_functions = require('../../lib/errors'); -const log_message = require('../../configs/log_message'); -const api_code = require('../../configs/api_code'); const defaultContainerName = require('../../configs/OS').defaultContainerName; +import auth from '../auth'; + +import * as server_functions from '../../lib/server_functions'; +import * as log_functions from '../../lib/log_functions'; + +import api_code from '../../configs/api_code'; +import log_message from '../../configs/log_message'; + +const router = Router(); + // Preload server objects on routes with ':server' -router.param('server', function (req, res, next, slug) { +router.param('server', function (req : any, res, next, slug) { Server.findOne({ slug: slug }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server ' + slug + ' not found' } }); } req.server = server; @@ -24,12 +27,13 @@ router.param('server', function (req, res, next, slug) { }).catch(next); }); -router.get('/', auth.required, function (req, res, next) { +router.get('/', auth.required, function (req : any, res, next) { - User.findById(req.payload.id).then(function (user) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { log_functions.create('error', 'get /server/', - log_message.user_account_unknown + user, user, req.server); + log_message.user_account_unknown + user, + user, req.server); return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { @@ -44,16 +48,17 @@ router.get('/', auth.required, function (req, res, next) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } var author = req.query.author; - user.findAnUser(author).then(function (results) { + user.findAnUser(author).then(function (results : any) { author = results[0]; console.log(author); - user.findAllServersOfAnUser(req.query, author, req.payload).then(function (results) { + user.findAllServersOfAnUser(req.query, author, req.payload) + .then(function (results : any) { var servers = results[0]; var serversCount = results[1]; log_functions.create('general', 'get /server/', 'ok', user, req.server) return res.json({ - servers: servers.map(function (server) { + servers: servers.map(function (server : any) { return server.toJSONFor(author); }), serversCount: serversCount @@ -64,8 +69,8 @@ router.get('/', auth.required, function (req, res, next) { }); -router.post('/', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { log_functions.create('error', 'post /server/', log_message.user_account_unknown + user, user, req.server); @@ -85,13 +90,15 @@ router.post('/', auth.required, function (req, res, next) { server.author = user; log_functions.create('bin', 'post /server/', log_message.user_server_created, user, server); return server.save().then(function () { - server_functions.createSwiftContainer(server.slug).then((_) => { - server_functions.copySwiftContainer(defaultContainerName, server.slug).then(_ => { + server_functions.createSwiftContainer(server.slug) + .then(() => { + server_functions.copySwiftContainer(defaultContainerName, server.slug) + .then(() => { log_functions.create('general', 'post /server/', log_message.user_swift_created, user, server); console.log('swift created'); return res.json({ server: server.toJSONFor(user) }); }); - }, (err) => { + }, (err : any) => { log_functions.create('error', 'post /server/', log_message.user_swift_error, user, server); return res.status(api_code.error).send({ errors: { err } }); @@ -102,7 +109,7 @@ router.post('/', auth.required, function (req, res, next) { }); // return a server -router.get('/:server', auth.required, function (req, res, next) { +router.get('/:server', auth.required, function (req : any, res, next) { Promise.all([ req.payload ? User.findById(req.payload.id) : null, req.server.populate('author').execPopulate(), @@ -133,8 +140,8 @@ router.get('/:server', auth.required, function (req, res, next) { }); // update server -router.put('/:server', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.put('/:server', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user.active) { log_functions.create('error', 'put /server/:' + req.server.slug, log_message.user_account_error, user, req.server); @@ -164,7 +171,7 @@ router.put('/:server', auth.required, function (req, res, next) { req.server.body = req.body.server.body; } - req.server.save().then(function (server) { + req.server.save().then(function (server : any) { log_functions.create('bin', 'put /server/:' + req.server.slug, 'server information updated', user, req.server); return res.json({ server: server.toJSONFor(user) }); }).catch(next); @@ -177,8 +184,8 @@ router.put('/:server', auth.required, function (req, res, next) { }); //disable or enable a server -router.post('/disable/:server', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/disable/:server', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (req.server.author._id.toString() === req.payload.id.toString() || user.isAdmin()) { if (!user.active) { log_functions.create('error', 'post /server/disable/:' + req.server.slug, @@ -207,7 +214,8 @@ router.post('/disable/:server', auth.required, function (req, res, next) { user.startProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.user_processing_start, user); console.log('user.processing : ' + user.processing); - server_functions.shut_off(slug, namespace, volume).then((response) => { + server_functions.removekubelink(slug, namespace) + .then((response : any) => { user.endProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.user_processing_end, user); console.log('user.processing : ' + user.processing); @@ -217,7 +225,7 @@ router.post('/disable/:server', auth.required, function (req, res, next) { return res.sendStatus(api_code.ok); }); }); - }, (err) => { + }, (err : any) => { user.endProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.server_shut_off, user); return res.status(api_code.error).send({ errors: { err } }); @@ -229,7 +237,8 @@ router.post('/disable/:server', auth.required, function (req, res, next) { user.startProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.user_processing_start, user); console.log('user.processing : ' + user.processing); - server_functions.shut_on(slug, username, namespace).then((response) => { + server_functions.createkubelink(slug, username, namespace) + .then((response : any) => { user.endProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.user_processing_end, user); console.log('user.processing : ' + user.processing); @@ -240,7 +249,7 @@ router.post('/disable/:server', auth.required, function (req, res, next) { return res.sendStatus(api_code.ok); }); }); - }, (err) => { + }, (err : any) => { user.endProcessing().then(() => { log_functions.create('bin', 'post /server/disable/:' + req.server.slug, log_message.user_processing_end, user); return res.status(api_code.error).send({ errors: { err } }); @@ -257,8 +266,8 @@ router.post('/disable/:server', auth.required, function (req, res, next) { }); // delete server -router.delete('/:server', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.delete('/:server', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { log_functions.create('error', 'delete /server/:' + req.server.slug, log_message.user_account_unknown + user, user, req.server); @@ -291,7 +300,7 @@ router.delete('/:server', auth.required, function (req, res, next) { user.startProcessing().then(() => { log_functions.create('bin', 'delete /server/:' + req.server.slug, log_message.user_processing_start, user); - server_functions.delete(slug, namespace, './uploads/' + user.username + '/' + slug + '/').then((response) => { + server_functions.deleteAll(slug, namespace, './uploads/' + user.username + '/' + slug + '/').then((response : any) => { user.endProcessing().then(() => { log_functions.create('bin', 'delete /server/:' + req.server.slug, log_message.user_processing_end, user); log_functions.create('bin', 'delete /server/:' + req.server.slug, log_message.server_deletion_ok, user, req.server).then(() => { @@ -300,8 +309,9 @@ router.delete('/:server', auth.required, function (req, res, next) { }); }) }); - }, (err) => { + }, (err : any) => { user.endProcessing().then(() => { + console.error(err); log_functions.create('bin', 'delete /server/:' + req.server.slug, log_message.user_processing_end, user); return res.status(api_code.error).send({ errors: { err } }); }); @@ -315,8 +325,8 @@ router.delete('/:server', auth.required, function (req, res, next) { }).catch(next); }); -router.post('/token/:server', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/token/:server', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { log_functions.create('error', 'post /server/:' + req.server.slug, log_message.user_account_unknown + user, user, req.server); @@ -342,14 +352,14 @@ router.post('/token/:server', auth.required, function (req, res, next) { var slug = req.server.slug; var namespace = 'default'; user.startProcessing().then(() => server_functions.catchTeacherToken(slug, namespace)) - .then(token => { + .then((token : any) => { log_functions.create('bin', 'post /server/token:' + req.server.slug, log_message.user_token_ok, user, req.server); req.server.token = token; return req.server.save(); }) .then(() => user.endProcessing()) .then(() => res.json({ server: req.server.toJSONFor(user) })) - .catch(async err => { + .catch(async (err : any) => { await user.endProcessing(); log_functions.create('error', 'post /server/', log_message.user_token_error + req.server.slug, diff --git a/BackEnd/routes/api/upload.js b/BackEnd/src/routes/api/upload.ts similarity index 79% rename from BackEnd/routes/api/upload.js rename to BackEnd/src/routes/api/upload.ts index 26df326..a82534c 100644 --- a/BackEnd/routes/api/upload.js +++ b/BackEnd/src/routes/api/upload.ts @@ -1,10 +1,14 @@ -/*eslint-disable*/ -const router = require('express').Router(); +import { Router } from 'express'; const mongoose = require('mongoose'); const multer = require('multer'); -const auth = require('../auth'); const path = require('path'); -const api_code = require('../../configs/api_code'); + +import auth from '../auth'; + +import * as upload_functions from '../../lib/upload_functions'; +import upload_errors from '../../lib/errors'; + +import api_code from '../../configs/api_code'; const dirPath = './uploads/'; var destPath = ''; @@ -32,24 +36,25 @@ const exercisesDir = 'exercises/'; var User = mongoose.model('User'); var Server = mongoose.model('Server'); -const upload_functions = require('../../lib/upload_functions'); -const upload_errors = require('../../lib/errors'); + let storage = multer.diskStorage({ - destination: (req, file, cb) => { + destination: (req : any, file : any, cb : any) => { cb(null, dirPath); }, - filename: (req, file, cb) => { + filename: (req : any, file : any, cb : any) => { destPath = path.extname(file.originalname); cb(null, destPath); } }); let upload = multer({ storage: storage }); +const router = Router(); + // Preload server objects on routes with ':server' -router.param('server', function (req, res, next, slug) { +router.param('server', function (req : any, res, next, slug) { Server.findOne({ slug: slug }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server ' + slug + ' not found' } }); } req.server = server; @@ -58,18 +63,18 @@ router.param('server', function (req, res, next, slug) { }).catch(next); }); -router.get('/', auth.required, function (req, res) { +router.get('/', auth.required, function (req : any, res) { res.end('file catcher example'); }); -router.post('/index', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/index', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } Server.findOne({ slug: req.body.server }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server not found' } }); } if ((server.author.username !== user.username) && (!user.isAdmin())) { console.log(server.author.username); @@ -78,18 +83,18 @@ router.post('/index', auth.required, function (req, res, next) { } var dest_path = dirPath + server.author.username + '/' + server.slug + '/'; upload_functions.loadIndexJson(dest_path + save_folder) - .catch(error => { + .catch((error : any) => { if (error.code === 'ENOENT') { return []; } else { throw error; } }) - .then((groups) => { - upload_functions.checkFiles(dest_path + dirt_folder).then((files_sended) => { - var files = []; - upload_functions.checkFiles(dest_path + safe_folder).then((files_saved) => { - files_saved.forEach(element => { + .then((groups : any) => { + upload_functions.checkFiles(dest_path + dirt_folder).then((files_sended : any) => { + var files : any = []; + upload_functions.checkFiles(dest_path + safe_folder).then((files_saved : any) => { + files_saved.forEach((element : any) => { if (!files_sended.includes(element)) { files.push(element); } @@ -98,15 +103,15 @@ router.post('/index', auth.required, function (req, res, next) { name: files, group: groups }); - }, (err) => { + }, (err : any) => { console.log('Error checkFiles !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); - }, (err) => { + }, (err : any) => { console.log('Error checkFiles !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); - }, (err) => { + }, (err : any) => { console.log('Error loading tabofName !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); @@ -114,14 +119,14 @@ router.post('/index', auth.required, function (req, res, next) { }).catch(next); }); -router.post('/check', auth.required, upload.single('file'), function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/check', auth.required, upload.single('file'), function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } Server.findOne({ slug: req.body.server }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server not found' } }); } if ((server.author.username !== user.username) && (!user.isAdmin())) { console.log(server.author.username); @@ -141,17 +146,17 @@ router.post('/check', auth.required, upload.single('file'), function (req, res, mimetype === 'application/octet-stream' || mimetype === 'application/x-zip-compressed') { console.log('file received'); - upload_functions.createArbo(dest_path, server.slug + '/', safe_folder, dirt_folder, save_folder, download_folder).then((response) => { - upload_functions.archive_traitement(dest_path + server.slug + '/', source_path, archive_folder, safe_folder, '').then((files) => { + upload_functions.createArbo(dest_path, server.slug + '/', safe_folder, dirt_folder, save_folder, download_folder).then((response : any) => { + upload_functions.archive_traitement(dest_path + server.slug + '/', source_path, archive_folder, safe_folder, '').then((files : any) => { console.log(files); return res.json({ name: files, }); - }, (err) => { + }, (err : any) => { console.log('Error archive traitement !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); - }, (err) => { + }, (err : any) => { console.log('Error createArbo !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); @@ -165,14 +170,14 @@ router.post('/check', auth.required, upload.single('file'), function (req, res, }); -router.post('/full', auth.required, upload.single('file'), function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/full', auth.required, upload.single('file'), function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } Server.findOne({ slug: req.body.server }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server not found' } }); } if ((server.author.username !== user.username) && (!user.isAdmin())) { console.log(server.author.username); @@ -210,48 +215,48 @@ router.post('/full', auth.required, upload.single('file'), function (req, res, n console.log('full archive file received'); upload_functions.createArbo(userDirPath, serverDir, safe_folder, dirt_folder, save_folder, download_folder) - .catch(err => upload_errors.wrap_error('createArbo', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createArbo', api_code.error, err)) .then(() => upload_functions.removeDir(uploadDirPath)) - .catch(err => upload_errors.wrap_error('removeDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('removeDir', api_code.error, err)) .then(() => upload_functions.createDir(uploadDirPath)) .then(() => upload_functions.createDir(swiftDirPath)) - .catch(err => upload_errors.wrap_error('createDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createDir', api_code.error, err)) .then(() => upload_functions.desarchived(uploadDirPath, archiveFilePath)) - .catch(err => upload_errors.wrap_error('desarchived', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('desarchived', api_code.error, err)) .then(() => upload_functions.removeDir(archiveFilePath)) .then(() => upload_functions.copyFile(indexJSONPath, saveIndexJSONPath)) - .catch(err => upload_errors.wrap_error('copyFile', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('copyFile', api_code.error, err)) .then(() => upload_functions.copyDir(exercisesPath, safePath)) .then(() => upload_functions.copyDir(exercisesPath, dirtPath)) - .catch(err => upload_errors.wrap_error('copyDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('copyDir', api_code.error, err)) .then(() => upload_functions.createArchiveFromDirectory(repositoryDirPath, repositoryDir, archive_extension, repositoryNamePath)) - .catch(err => upload_errors.wrap_error('createArchiveFromDirectory sync', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createArchiveFromDirectory sync', api_code.error, err)) .then(() => upload_functions.sendToSwift(path.resolve(swiftDirPath + repositoryArchive), server.slug, repositoryArchive)) - .catch(err => upload_errors.wrap_error('sendToSwift', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('sendToSwift', api_code.error, err)) .then(() => upload_functions.fileExists(syncDirPath)) - .then(async syncExists => { + .then(async (syncExists : any) => { console.log("syncExists"); console.log(syncExists); if(syncExists) { await upload_functions.createArchiveFromDirectory(syncDirPath, syncDir, archive_extension, syncNamePath) - .catch(err => upload_errors.wrap_error('createArchiveFromDirectory sync', + .catch((err : any) => upload_errors.wrap_error('createArchiveFromDirectory sync', api_code.error, err)) .then(() => upload_functions.sendToSwift(path.resolve(swiftDirPath + syncArchive), server.slug, syncArchive)) - .catch(err => upload_errors.wrap_error('sendToSwift', api_code.error, err)); + .catch((err : any) => upload_errors.wrap_error('sendToSwift', api_code.error, err)); }}) .then(() => res.sendStatus(api_code.ok)) - .catch(err => upload_errors.unwrap_error(res, err)); + .catch((err : any) => upload_errors.unwrap_error(res, err)); } else { console.error('Bad file Format : ' + req.file.mimetype + '\nExpected .zip'); return res.status(api_code.error) @@ -263,14 +268,14 @@ router.post('/full', auth.required, upload.single('file'), function (req, res, n }); -router.post('/url', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/url', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } Server.findOne({ slug: req.body.server }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Server not found' } }); } if ((server.author.username !== user.username) && (!user.isAdmin())) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } console.log(req.body); @@ -280,27 +285,27 @@ router.post('/url', auth.required, function (req, res, next) { if (upload_functions.parse_url(file_url) !== 'github.com') { return res.status(api_code.error).json({ errors: { errors: ': URL invalid' } }); } - upload_functions.createArbo(dest_path, server.slug + '/', safe_folder, dirt_folder, save_folder, download_folder).then((response) => { + upload_functions.createArbo(dest_path, server.slug + '/', safe_folder, dirt_folder, save_folder, download_folder).then((response : any) => { upload_functions.createDir(dest_path + server.slug + '/' + DOWNLOAD_DIR).then(() => { - upload_functions.download_from_url(file_url, dest_path + server.slug + '/' + DOWNLOAD_DIR).then((source_path) => { - upload_functions.archive_traitement(dest_path + server.slug + '/', source_path, archive_folder, safe_folder, '/exercises').then((files) => { + upload_functions.download_from_url(file_url, dest_path + server.slug + '/' + DOWNLOAD_DIR).then((source_path : any) => { + upload_functions.archive_traitement(dest_path + server.slug + '/', source_path, archive_folder, safe_folder, '/exercises').then((files : any) => { console.log(files); return res.json({ name: files, }); - }, (err) => { + }, (err : any) => { console.log('Error archive traitement !: ' + err); return res.status(api_code.error).json({ errors: err }); }); - }, (err) => { + }, (err : any) => { console.log('Error createArbo !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); - }, (err) => { + }, (err : any) => { console.log('Error getRepo !: ' + err); return res.status(api_code.error).json({ errors: { errors: err.message } }); }); - }, (err) => { + }, (err : any) => { console.log('Error download from url !: ' + err); var message = upload_errors.wget_error(err.code) + err.message; return res.status(api_code.error).send({ errors: { message } }); @@ -310,14 +315,14 @@ router.post('/url', auth.required, function (req, res, next) { }); -router.post('/send', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/send', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } Server.findOne({ slug: req.body.server }) .populate('author') - .then(function (server) { + .then(function (server : any) { if (!server) { return res.sendStatus(api_code.not_found).json({ errors: { errors: 'Not found' } }); } if ((server.author.username !== user.username) && (!user.isAdmin())) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } var dir = './uploads/' + server.author.username + '/' + server.slug + '/'; @@ -341,11 +346,11 @@ router.post('/send', auth.required, function (req, res, next) { dirtExercisePath = path.resolve(dir, dirt_folder, exercise); return upload_functions.removeDir(safeExercisePath) - .catch(err => upload_errors.wrap_error('removeDir',api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('removeDir',api_code.error, err)) .then(() => console.log(safeExercisePath + ' removed')) .then(() => upload_functions.removeDir(dirtExercisePath)) - .catch(err => upload_errors.wrap_error('removeDir',api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('removeDir',api_code.error, err)) .then(() => console.log(dirtExercisePath + ' removed')); })); @@ -353,55 +358,55 @@ router.post('/send', auth.required, function (req, res, next) { } }) .then(() => upload_functions.checkFiles(dir + safe_folder)) - .catch(err => upload_errors.wrap_error('checkFiles', api_code.error, err)) - .then((files) => + .catch((err : any) => upload_errors.wrap_error('checkFiles', api_code.error, err)) + .then((files : any) => upload_functions.copyDir(dir + safe_folder, dir + dirt_folder) - .catch(err => upload_errors.wrap_error('copyDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('copyDir', api_code.error, err)) .then(() => upload_functions.delete_useless_files(req.body.useless, dir + dirt_folder, tabOfName, files)) - .catch(err => upload_errors.wrap_error('delete_useless_files', api_code.error, err))) - .then((tabOfName_bis) => upload_functions.create_new_tabOfName(dir + save_folder, + .catch((err : any) => upload_errors.wrap_error('delete_useless_files', api_code.error, err))) + .then((tabOfName_bis : any) => upload_functions.create_new_tabOfName(dir + save_folder, dir + dirt_folder, tabOfName_bis)) - .catch(err => upload_errors.wrap_error('create_new_tabOfName', api_code.error, err)) - .then((new_tabOfName) => { + .catch((err : any) => upload_errors.wrap_error('create_new_tabOfName', api_code.error, err)) + .then((new_tabOfName : any) => { let sourcePath = dir + dirt_folder; let destPath = repositoryDir + exercisesDir; let archivePath = sourcePath + archive_folder; let repositoryPath = archivePath + repositoryName; upload_functions.create_indexJSON(dir + dirt_folder + 'index.json', new_tabOfName) - .catch(err => upload_errors.wrap_error('create_indexJSON', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('create_indexJSON', api_code.error, err)) .then(() => upload_functions.createDir(dir + dirt_folder + archive_folder)) - .catch(err => upload_errors.wrap_error('createDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createDir', api_code.error, err)) .then(() => upload_functions.copyFile(dir + save_folder + indexJSON, sourcePath + indexJSON)) - .catch(err => upload_errors.wrap_error('copyFile index.json', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('copyFile index.json', api_code.error, err)) .then(() => upload_functions.createArchiveFromDirectory(sourcePath, destPath, archive_extension, repositoryPath)) - .catch(err => upload_errors.wrap_error('createArchiveFromDirectory', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createArchiveFromDirectory', api_code.error, err)) .then(() => upload_functions.sendToSwift(path.resolve(archivePath + repositoryArchive), server.slug, repositoryArchive)) - .catch(err => upload_errors.wrap_error('sendToSwift', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('sendToSwift', api_code.error, err)) .then(() => upload_functions.removeDir(archivePath)) - .catch(err => upload_errors.wrap_error('archivePath', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('archivePath', api_code.error, err)) .finally(() => user.endProcessing()) .finally(() => console.log('user.processing : ' + user.processing)) .then(() => res.send({ success: true, message: 'ok' })) - .catch(err => upload_errors.unwrap_error(res, err)); + .catch((err : any) => upload_errors.unwrap_error(res, err)); }).catch(next); }).catch(next); }); }); -router.post('/download/:server', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/download/:server', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } @@ -430,40 +435,40 @@ router.post('/download/:server', auth.required, function (req, res, next) { let allPathDir = allPath + '/'; upload_functions.removeDir(allPath + '.' + archive_extension) .then(() => upload_functions.removeDir(allPathDir)) - .catch(err => upload_errors.wrap_error('removeDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('removeDir', api_code.error, err)) .then(() => upload_functions.createDir(allPathDir)) - .catch(err => upload_errors.wrap_error('createDir', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createDir', api_code.error, err)) .then(() => upload_functions.desarchived(allPathDir, downloadPathDir + repositoryArchive)) .then(() => upload_functions.fileExists(downloadPathDir + syncArchive)) - .then(syncExist => (syncExist) ? upload_functions.desarchived(allPathDir, + .then((syncExist : any) => (syncExist) ? upload_functions.desarchived(allPathDir, downloadPathDir + syncArchive) : undefined) - .catch(err => upload_errors.wrap_error('desarchived', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('desarchived', api_code.error, err)) .then(() => upload_functions.createArchiveFromDirectory(allPathDir, '', archive_extension, allPath)) - .catch(err => upload_errors.wrap_error('createArchiveFromDirectory', api_code.error, err)) + .catch((err : any) => upload_errors.wrap_error('createArchiveFromDirectory', api_code.error, err)) .then(() => user.endProcessing()) .then(() => console.log('user.processing : ' + user.processing)) .then(() => res.sendFile(path.resolve(allPath + '.' + archive_extension))) - .catch(err => upload_errors.unwrap_error(res, err)); + .catch((err : any) => upload_errors.unwrap_error(res, err)); } else { user.endProcessing().then(() => { console.log('user.processing : ' + user.processing); res.sendFile(path.resolve(dest_path + download_folder + folderName + '.' + archive_extension)); }); } - }, (err) => { + }, (err : any) => { console.log('Error getFromSwift !: ' + err); user.endProcessing().then(() => { return res.status(api_code.error).json({ errors: { errors: err.message } }); }); }); - }, (err) => { + }, (err : any) => { console.log('Error create arbo !: ' + err); user.endProcessing().then(() => { return res.status(api_code.error).json({ errors: { errors: err.message } }); @@ -474,4 +479,3 @@ router.post('/download/:server', auth.required, function (req, res, next) { }); module.exports = router; - diff --git a/BackEnd/routes/api/users.js b/BackEnd/src/routes/api/users.ts similarity index 84% rename from BackEnd/routes/api/users.js rename to BackEnd/src/routes/api/users.ts index 5d904af..250cb2c 100644 --- a/BackEnd/routes/api/users.js +++ b/BackEnd/src/routes/api/users.ts @@ -1,24 +1,27 @@ +import { Router } from 'express'; var mongoose = require('mongoose'); -var router = require('express').Router(); var passport = require('passport'); var User = mongoose.model('User'); -var auth = require('../auth'); -var events = require('events'); -const user_functions = require('../../lib/user_functions'); -const server_functions = require('../../lib/server_functions'); -const global_functions = require('../../lib/global_functions'); -const api_code = require('../../configs/api_code'); - -router.get('/user', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { + +import auth from '../auth'; + +import * as server_functions from '../../lib/server_functions'; +import * as global_functions from '../../lib/global_functions'; + +import api_code from '../../configs/api_code'; + +const router = Router(); + +router.get('/user', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } return res.json({ user: user.toAuthJSON() }); }).catch(next); }); -router.get('/users', auth.required, function (req, res, next) { - var query = {}; +router.get('/users', auth.required, function (req : any, res, next) { + var query : any = {}; var limit = 20; var offset = 0; console.log(' req.query.limit ' + req.query.limit); @@ -42,11 +45,11 @@ router.get('/users', auth.required, function (req, res, next) { query.authorized = req.query.authorized; } - User.findById(req.payload.id).then(function (user) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.isAdmin()) { - return user.findAllUsers(query, limit, offset).then(function (results) { + return user.findAllUsers(query, limit, offset).then(function (results : any) { var users = results[0]; var usersCount = results[1]; @@ -61,16 +64,16 @@ router.get('/users', auth.required, function (req, res, next) { }).catch(next); }); -router.put('/user', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.put('/user', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.active) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.isAdmin() && !user.authorized) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } - var userToMdify = 'undefined'; + var userToMdify : any = 'undefined'; if (user.isAdmin() && (req.body.userBase.username !== 'undefined')) { - User.find({ username: req.body.userBase.username }).then(function (response) { + User.find({ username: req.body.userBase.username }).then(function (response : any) { userToMdify = response[0]; }); } @@ -108,7 +111,7 @@ router.put('/user', auth.required, function (req, res, next) { }).catch(next); }); -router.post('/users/login', function (req, res, next) { +router.post('/users/login', function (req : any, res, next) { if (!req.body.user.email) { return res.status(api_code.error).json({ errors: { email: "can't be blank" } }); } @@ -117,7 +120,7 @@ router.post('/users/login', function (req, res, next) { return res.status(api_code.error).json({ errors: { password: "can't be blank" } }); } - passport.authenticate('local', { session: false }, function (err, user, info) { + passport.authenticate('local', { session: false }, function (err : any, user : any, info : any) { if (err) { return next(err); } if (user) { @@ -129,7 +132,7 @@ router.post('/users/login', function (req, res, next) { })(req, res, next); }); -router.post('/reset-password', auth.required, function (req, res, next) { +router.post('/reset-password', auth.required, function (req : any, res, next) { if (!req.body.reset.new_password) { return res.status(api_code.error).json({ errors: { password: "can't be blank" } }); @@ -143,7 +146,7 @@ router.post('/reset-password', auth.required, function (req, res, next) { return res.status(api_code.error).json({ errors: { password: "verification mismatch" } }); } - User.findById(req.payload.id).then(function (user) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.active) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } @@ -174,8 +177,8 @@ router.post('/reset-password', auth.required, function (req, res, next) { }); //disable or enable an user -router.post('/users/disable', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/users/disable', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (!user.authorized && !user.isAdmin()) { return res.sendStatus(api_code.forbidden).json({ errors: { errors: 'Unauthorized' } }); } if (user.processing) { return res.sendStatus(api_code.forbidden); } @@ -215,11 +218,11 @@ router.post('/users/disable', auth.required, function (req, res, next) { var authors = req.body.disable.username_verification; - user.findAnUser(authors).then(function (results) { + user.findAnUser(authors).then(function (results : any) { - author = results[0]; + const author : any = results[0]; - user.findAllServersOfAnUser(req.query, author, req.payload).then(function (results) { + user.findAllServersOfAnUser(req.query, author, req.payload).then(function (results : any) { var servers = results[0]; if (servers.length == 0) { author.active = !author.active; @@ -234,18 +237,18 @@ router.post('/users/disable', auth.required, function (req, res, next) { } var itemsProcessed = 0; - servers.forEach((server, index, array) => { + servers.forEach((server : any, index : any, array : any) => { global_functions.asyncFunction(server, () => { if (server.active && user.active) { console.log('preparing shut_off'); var namespace = 'default'; - server_functions.shut_off(server.slug, namespace, server.volume).then((response) => { + server_functions.removekubelink(server.slug, namespace).then((response : any) => { server.active = false; server.save(); - }, (err) => { + }, (err : any) => { // return res.status(api_code.error).send({ errors: { err } }); console.log(err); }); @@ -276,8 +279,8 @@ router.post('/users/disable', auth.required, function (req, res, next) { }); //delete an user -router.post('/users/delete', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/users/delete', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden); } if (!user.authorized && !user.isAdmin()) { return res.sendStatus(api_code.forbidden); } if (user.processing) { return res.sendStatus(api_code.forbidden); } @@ -316,11 +319,11 @@ router.post('/users/delete', auth.required, function (req, res, next) { var authors = req.body.disable.username_verification; console.log('author = ' + authors); - user.findAnUser(authors).then(function (results) { + user.findAnUser(authors).then(function (results : any) { - author = results[0]; + const author : any = results[0]; console.log('author = ' + author); - user.findAllServersOfAnUser(req.query, author, req.payload).then(function (results) { + user.findAllServersOfAnUser(req.query, author, req.payload).then(function (results : any) { var servers = results[0]; if (servers.length == 0) { author.remove(); @@ -330,18 +333,15 @@ router.post('/users/delete', auth.required, function (req, res, next) { var namespace = 'default'; var itemsProcessed = 0; var itemToDelete = servers.length; - servers.forEach((server, index, array) => { + servers.forEach((server : any, index : any, array : any) => { global_functions.asyncFunction(server, () => { console.log('asking for a deletion'); console.log('slug : ' + server.slug); console.log('namespace : ' + namespace); - server_functions.delete(server.slug, namespace).then((response) => { + server_functions.deleteAll(server.slug, namespace, './uploads/' + user.username + '/' + server.slug + '/').then((response : any) => { itemToDelete--; server.remove(); }); - }, (err) => { - console.log(err); - // return res.status(api_code.error).send({ errors: { err } }); }); itemsProcessed++; if (itemsProcessed === array.length) { @@ -364,7 +364,7 @@ router.post('/users/delete', auth.required, function (req, res, next) { }).catch(next); }); -router.post('/users', function (req, res, next) { +router.post('/users', function (req : any, res, next) { var user = new User(); user.username = req.body.user.username; @@ -387,11 +387,11 @@ router.post('/users', function (req, res, next) { }).catch(next); }); -router.post('/user/activate', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/user/activate', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden); } if (!user.isAdmin()) { return res.sendStatus(api_code.forbidden); } - user.findAnUser(req.body.user.username).then(function (userToActivate) { + user.findAnUser(req.body.user.username).then(function (userToActivate : any) { userToActivate[0].authorized = true; userToActivate[0].active = true; userToActivate[0].save().then(function () { @@ -401,11 +401,11 @@ router.post('/user/activate', auth.required, function (req, res, next) { }).catch(next); }); -router.post('/user/authorize', auth.required, function (req, res, next) { - User.findById(req.payload.id).then(function (user) { +router.post('/user/authorize', auth.required, function (req : any, res, next) { + User.findById(req.payload.id).then(function (user : any) { if (!user) { return res.sendStatus(api_code.forbidden); } if (!user.isAdmin()) { return res.sendStatus(api_code.forbidden); } - user.findAnUser(req.body.user.username).then(function (userToActivate) { + user.findAnUser(req.body.user.username).then(function (userToActivate : any) { userToActivate[0].authorized = true; userToActivate[0].processing = false; userToActivate[0].save().then(function () { diff --git a/BackEnd/routes/auth.js b/BackEnd/src/routes/auth.ts similarity index 78% rename from BackEnd/routes/auth.js rename to BackEnd/src/routes/auth.ts index 582fcf9..0b2e45f 100644 --- a/BackEnd/routes/auth.js +++ b/BackEnd/src/routes/auth.ts @@ -1,7 +1,8 @@ -var jwt = require('express-jwt'); -var secret = require('../configs').secret; +const jwt = require('express-jwt'); -function getTokenFromHeader(req) { +import { secret } from '../configs'; + +function getTokenFromHeader(req : any) { if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Token' || req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') { return req.headers.authorization.split(' ')[1]; @@ -10,7 +11,7 @@ function getTokenFromHeader(req) { return null; } -var auth = { +const auth = { required: jwt({ secret: secret, userProperty: 'payload', @@ -26,4 +27,4 @@ var auth = { }) }; -module.exports = auth; +export default auth; diff --git a/BackEnd/routes/index.js b/BackEnd/src/routes/index.ts similarity index 100% rename from BackEnd/routes/index.js rename to BackEnd/src/routes/index.ts diff --git a/BackEnd/tsconfig-build.json b/BackEnd/tsconfig-build.json new file mode 100644 index 0000000..9049470 --- /dev/null +++ b/BackEnd/tsconfig-build.json @@ -0,0 +1,6 @@ +{ + "extends" : "./tsconfig.json", + "exclude" : [ + "test/**/*.ts" + ] +} diff --git a/BackEnd/tsconfig.json b/BackEnd/tsconfig.json new file mode 100644 index 0000000..5378855 --- /dev/null +++ b/BackEnd/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions" : { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Basic Options */ + "lib" : [ "es2020" ], + "module" : "commonjs", + "outDir" : "./dist", + "sourceMap" : true, + "target" : "es6", + + /* Strict Type-Checking Options */ + "strict" : true, + "emitDecoratorMetadata" : true, + "experimentalDecorators" : true, + + /* Module Resolution Options */ + "moduleResolution" : "node", + "esModuleInterop" : true + }, + "include" : [ + "src/**/*.ts", + "test/**/*.ts", + ] +}