mirror of
https://github.com/sasjs/server.git
synced 2025-12-11 19:44:35 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a07f47a1ba | ||
|
|
2548c82dfe | ||
|
|
238aa1006f | ||
|
|
35cba97611 | ||
|
|
5f29dec16f | ||
|
|
e2a97fcb7c | ||
|
|
6adeeefcf5 | ||
|
|
c9d66b8576 | ||
|
|
5aaac24080 | ||
|
|
6d34206bbc | ||
|
|
7b39cc06d3 | ||
|
|
6e7f28a6f8 | ||
|
|
5689169ce4 | ||
|
|
6139e7bff6 | ||
|
|
2c77317bb9 | ||
|
|
57b63db9cb | ||
|
|
60a2a4fe32 |
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -8,10 +8,20 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
node-version: [lts/*]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
uses: actions/setup-node@v2
|
||||||
|
with:
|
||||||
|
node-version: ${{ matrix.node-version }}
|
||||||
|
|
||||||
- name: Install Dependencies WEB
|
- name: Install Dependencies WEB
|
||||||
working-directory: ./web
|
working-directory: ./web
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
43
CHANGELOG.md
43
CHANGELOG.md
@@ -2,6 +2,49 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||||
|
|
||||||
|
### [0.0.68](https://github.com/sasjs/server/compare/v0.0.67...v0.0.68) (2022-05-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* using monaco editor locally ([2548c82](https://github.com/sasjs/server/commit/2548c82dfe1149e62a570a00546dddd9e30049b1))
|
||||||
|
|
||||||
|
### [0.0.67](https://github.com/sasjs/server/compare/v0.0.66...v0.0.67) (2022-05-01)
|
||||||
|
|
||||||
|
### [0.0.66](https://github.com/sasjs/server/compare/v0.0.64...v0.0.66) (2022-05-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* added swagger ui init file manually ([e2a97fc](https://github.com/sasjs/server/commit/e2a97fcb7c54a57a7ca118677cfce93fe9430d8f))
|
||||||
|
* consume swagger api with CSRF ([5aaac24](https://github.com/sasjs/server/commit/5aaac24080362d6ce0c5d1157798a9343f40ae2a))
|
||||||
|
|
||||||
|
### [0.0.65](https://github.com/sasjs/server/compare/v0.0.64...v0.0.65) (2022-05-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* consume swagger api with CSRF ([5aaac24](https://github.com/sasjs/server/commit/5aaac24080362d6ce0c5d1157798a9343f40ae2a))
|
||||||
|
|
||||||
|
### [0.0.64](https://github.com/sasjs/server/compare/v0.0.63...v0.0.64) (2022-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* removed fileExists for serving web ([7b39cc0](https://github.com/sasjs/server/commit/7b39cc06d358f5ffecb87955040c4eb0fcc7469e))
|
||||||
|
|
||||||
|
### [0.0.63](https://github.com/sasjs/server/compare/v0.0.62...v0.0.63) (2022-04-30)
|
||||||
|
|
||||||
|
### [0.0.62](https://github.com/sasjs/server/compare/v0.0.61...v0.0.62) (2022-04-30)
|
||||||
|
|
||||||
|
### [0.0.61](https://github.com/sasjs/server/compare/v0.0.59...v0.0.61) (2022-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* added CSRF check for granting access via session authentication ([b060ad1](https://github.com/sasjs/server/commit/b060ad1b8e0bbc61c20dc25be553bba4cc4d2716))
|
||||||
|
* setting CSRF Token for only rendering SPA ([b4b60c6](https://github.com/sasjs/server/commit/b4b60c69cf67a42f4797f7f1afe68b7a5eec2998))
|
||||||
|
|
||||||
### [0.0.60](https://github.com/sasjs/server/compare/v0.0.59...v0.0.60) (2022-04-30)
|
### [0.0.60](https://github.com/sasjs/server/compare/v0.0.59...v0.0.60) (2022-04-30)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
60
api/package-lock.json
generated
60
api/package-lock.json
generated
@@ -24,7 +24,7 @@
|
|||||||
"mongoose-sequence": "^5.3.1",
|
"mongoose-sequence": "^5.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.3",
|
"multer": "^1.4.3",
|
||||||
"swagger-ui-express": "^4.1.6"
|
"swagger-ui-express": "4.3.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"api": "build/src/server.js"
|
"api": "build/src/server.js"
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
"mongodb-memory-server": "^8.0.0",
|
"mongodb-memory-server": "^8.0.0",
|
||||||
"nodemon": "^2.0.7",
|
"nodemon": "^2.0.7",
|
||||||
"pkg": "5.5.2",
|
"pkg": "5.6.0",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"supertest": "^6.1.3",
|
"supertest": "^6.1.3",
|
||||||
@@ -8170,9 +8170,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pkg": {
|
"node_modules/pkg": {
|
||||||
"version": "5.5.2",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg/-/pkg-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz",
|
||||||
"integrity": "sha512-pD0UB2ud01C6pVv2wpGsTYJrXI/bnvGRYvMLd44wFzA1p+A2jrlTGFPAYa7YEYzmitXhx23PqalaG1eUEnSwcA==",
|
"integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/parser": "7.16.2",
|
"@babel/parser": "7.16.2",
|
||||||
@@ -8184,7 +8184,7 @@
|
|||||||
"into-stream": "^6.0.0",
|
"into-stream": "^6.0.0",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"multistream": "^4.1.0",
|
"multistream": "^4.1.0",
|
||||||
"pkg-fetch": "3.2.6",
|
"pkg-fetch": "3.3.0",
|
||||||
"prebuild-install": "6.1.4",
|
"prebuild-install": "6.1.4",
|
||||||
"progress": "^2.0.3",
|
"progress": "^2.0.3",
|
||||||
"resolve": "^1.20.0",
|
"resolve": "^1.20.0",
|
||||||
@@ -8216,9 +8216,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pkg-fetch": {
|
"node_modules/pkg-fetch": {
|
||||||
"version": "3.2.6",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz",
|
||||||
"integrity": "sha512-Q8fx6SIT022g0cdSE4Axv/xpfHeltspo2gg1KsWRinLQZOTRRAtOOaEFghA1F3jJ8FVsh8hGrL/Pb6Ea5XHIFw==",
|
"integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
@@ -8275,9 +8275,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pkg-fetch/node_modules/semver": {
|
"node_modules/pkg-fetch/node_modules/semver": {
|
||||||
"version": "7.3.5",
|
"version": "7.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
@@ -9434,11 +9434,11 @@
|
|||||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||||
},
|
},
|
||||||
"node_modules/swagger-ui-express": {
|
"node_modules/swagger-ui-express": {
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.3.0.tgz",
|
||||||
"integrity": "sha512-znrHTwh9UpvsjqgWopA4noIet7mi7UGuIYZ465YfUDKQ5Dpas0jxnkfUKCo+0aB17YCBv26AhIjiQYDV4uvJFA==",
|
"integrity": "sha512-jN46SEEe9EoXa3ZgZoKgnSF6z0w3tnM1yqhO4Y+Q4iZVc8JOQB960EZpIAz6rNROrDApVDwcMHR0mhlnc/5Omw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"swagger-ui-dist": ">3.52.5"
|
"swagger-ui-dist": ">=4.1.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= v0.10.32"
|
"node": ">= v0.10.32"
|
||||||
@@ -16649,9 +16649,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pkg": {
|
"pkg": {
|
||||||
"version": "5.5.2",
|
"version": "5.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg/-/pkg-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/pkg/-/pkg-5.6.0.tgz",
|
||||||
"integrity": "sha512-pD0UB2ud01C6pVv2wpGsTYJrXI/bnvGRYvMLd44wFzA1p+A2jrlTGFPAYa7YEYzmitXhx23PqalaG1eUEnSwcA==",
|
"integrity": "sha512-mHrAVSQWmHA41RnUmRpC7pK9lNnMfdA16CF3cqOI22a8LZxOQzF7M8YWtA2nfs+d7I0MTDXOtkDsAsFXeCpYjg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/parser": "7.16.2",
|
"@babel/parser": "7.16.2",
|
||||||
@@ -16663,7 +16663,7 @@
|
|||||||
"into-stream": "^6.0.0",
|
"into-stream": "^6.0.0",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.5",
|
||||||
"multistream": "^4.1.0",
|
"multistream": "^4.1.0",
|
||||||
"pkg-fetch": "3.2.6",
|
"pkg-fetch": "3.3.0",
|
||||||
"prebuild-install": "6.1.4",
|
"prebuild-install": "6.1.4",
|
||||||
"progress": "^2.0.3",
|
"progress": "^2.0.3",
|
||||||
"resolve": "^1.20.0",
|
"resolve": "^1.20.0",
|
||||||
@@ -16720,9 +16720,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pkg-fetch": {
|
"pkg-fetch": {
|
||||||
"version": "3.2.6",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/pkg-fetch/-/pkg-fetch-3.3.0.tgz",
|
||||||
"integrity": "sha512-Q8fx6SIT022g0cdSE4Axv/xpfHeltspo2gg1KsWRinLQZOTRRAtOOaEFghA1F3jJ8FVsh8hGrL/Pb6Ea5XHIFw==",
|
"integrity": "sha512-xJnIZ1KP+8rNN+VLafwu4tEeV4m8IkFBDdCFqmAJz9K1aiXEtbARmdbEe6HlXWGSVuShSHjFXpfkKRkDBQ5kiA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chalk": "^4.1.2",
|
"chalk": "^4.1.2",
|
||||||
@@ -16764,9 +16764,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"semver": {
|
"semver": {
|
||||||
"version": "7.3.5",
|
"version": "7.3.7",
|
||||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
|
||||||
"integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
|
"integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"lru-cache": "^6.0.0"
|
"lru-cache": "^6.0.0"
|
||||||
@@ -17601,11 +17601,11 @@
|
|||||||
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
"integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
|
||||||
},
|
},
|
||||||
"swagger-ui-express": {
|
"swagger-ui-express": {
|
||||||
"version": "4.2.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/swagger-ui-express/-/swagger-ui-express-4.3.0.tgz",
|
||||||
"integrity": "sha512-znrHTwh9UpvsjqgWopA4noIet7mi7UGuIYZ465YfUDKQ5Dpas0jxnkfUKCo+0aB17YCBv26AhIjiQYDV4uvJFA==",
|
"integrity": "sha512-jN46SEEe9EoXa3ZgZoKgnSF6z0w3tnM1yqhO4Y+Q4iZVc8JOQB960EZpIAz6rNROrDApVDwcMHR0mhlnc/5Omw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"swagger-ui-dist": ">3.52.5"
|
"swagger-ui-dist": ">=4.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"symbol-tree": {
|
"symbol-tree": {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
"mongoose-sequence": "^5.3.1",
|
"mongoose-sequence": "^5.3.1",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"multer": "^1.4.3",
|
"multer": "^1.4.3",
|
||||||
"swagger-ui-express": "^4.1.6"
|
"swagger-ui-express": "4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bcryptjs": "^2.4.2",
|
"@types/bcryptjs": "^2.4.2",
|
||||||
@@ -85,7 +85,7 @@
|
|||||||
"jest": "^27.0.6",
|
"jest": "^27.0.6",
|
||||||
"mongodb-memory-server": "^8.0.0",
|
"mongodb-memory-server": "^8.0.0",
|
||||||
"nodemon": "^2.0.7",
|
"nodemon": "^2.0.7",
|
||||||
"pkg": "5.5.2",
|
"pkg": "5.6.0",
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"supertest": "^6.1.3",
|
"supertest": "^6.1.3",
|
||||||
|
|||||||
50
api/public/SASjsApi/swagger-ui-init.js
Normal file
50
api/public/SASjsApi/swagger-ui-init.js
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
window.onload = function () {
|
||||||
|
// Build a system
|
||||||
|
var url = window.location.search.match(/url=([^&]+)/)
|
||||||
|
if (url && url.length > 1) {
|
||||||
|
url = decodeURIComponent(url[1])
|
||||||
|
} else {
|
||||||
|
url = window.location.origin
|
||||||
|
}
|
||||||
|
var options = {
|
||||||
|
customOptions: {
|
||||||
|
url: '/swagger.yaml',
|
||||||
|
requestInterceptor: function (request) {
|
||||||
|
request.credentials = 'include'
|
||||||
|
var cookie = document.cookie
|
||||||
|
var startIndex = cookie.indexOf('XSRF-TOKEN')
|
||||||
|
var csrf = cookie.slice(startIndex + 11).split('; ')[0]
|
||||||
|
request.headers['X-XSRF-TOKEN'] = csrf
|
||||||
|
return request
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = options.swaggerUrl || url
|
||||||
|
var urls = options.swaggerUrls
|
||||||
|
var customOptions = options.customOptions
|
||||||
|
var spec1 = options.swaggerDoc
|
||||||
|
var swaggerOptions = {
|
||||||
|
spec: spec1,
|
||||||
|
url: url,
|
||||||
|
urls: urls,
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
|
||||||
|
plugins: [SwaggerUIBundle.plugins.DownloadUrl],
|
||||||
|
layout: 'StandaloneLayout'
|
||||||
|
}
|
||||||
|
for (var attrname in customOptions) {
|
||||||
|
swaggerOptions[attrname] = customOptions[attrname]
|
||||||
|
}
|
||||||
|
var ui = SwaggerUIBundle(swaggerOptions)
|
||||||
|
|
||||||
|
if (customOptions.oauth) {
|
||||||
|
ui.initOAuth(customOptions.oauth)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (customOptions.authAction) {
|
||||||
|
ui.authActions.authorize(customOptions.authAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
@@ -465,6 +465,21 @@ info:
|
|||||||
name: '4GL Ltd'
|
name: '4GL Ltd'
|
||||||
openapi: 3.0.0
|
openapi: 3.0.0
|
||||||
paths:
|
paths:
|
||||||
|
/:
|
||||||
|
get:
|
||||||
|
operationId: Home
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Ok
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
summary: 'Render index.html'
|
||||||
|
tags:
|
||||||
|
- Web
|
||||||
|
security: []
|
||||||
|
parameters: []
|
||||||
/login:
|
/login:
|
||||||
post:
|
post:
|
||||||
operationId: Login
|
operationId: Login
|
||||||
|
|||||||
@@ -1,10 +1,23 @@
|
|||||||
|
import path from 'path'
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { Request, Route, Tags, Post, Body, Get } from 'tsoa'
|
import { Request, Route, Tags, Post, Body, Get } from 'tsoa'
|
||||||
|
import { readFile } from '@sasjs/utils'
|
||||||
|
|
||||||
import User from '../model/User'
|
import User from '../model/User'
|
||||||
|
import { getWebBuildFolderPath } from '../utils'
|
||||||
|
|
||||||
@Route('/')
|
@Route('/')
|
||||||
@Tags('Web')
|
@Tags('Web')
|
||||||
export class WebController {
|
export class WebController {
|
||||||
|
/**
|
||||||
|
* @summary Render index.html
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Get('/')
|
||||||
|
public async home(@Request() req: express.Request) {
|
||||||
|
return home(req)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @summary Accept a valid username/password
|
* @summary Accept a valid username/password
|
||||||
*
|
*
|
||||||
@@ -31,6 +44,19 @@ export class WebController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const home = async (req: express.Request) => {
|
||||||
|
const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html')
|
||||||
|
|
||||||
|
// Attention! Cannot use fileExists here,
|
||||||
|
// due to limitation after building executable
|
||||||
|
const content = await readFile(indexHtmlPath)
|
||||||
|
|
||||||
|
req.res?.cookie('XSRF-TOKEN', req.csrfToken())
|
||||||
|
req.res?.setHeader('Content-Type', 'text/html')
|
||||||
|
|
||||||
|
return content
|
||||||
|
}
|
||||||
|
|
||||||
const login = async (
|
const login = async (
|
||||||
req: express.Request,
|
req: express.Request,
|
||||||
{ username, password }: LoginPayload
|
{ username, password }: LoginPayload
|
||||||
|
|||||||
@@ -36,12 +36,22 @@ router.use('/group', desktopRestrict, groupRouter)
|
|||||||
router.use('/stp', authenticateAccessToken, stpRouter)
|
router.use('/stp', authenticateAccessToken, stpRouter)
|
||||||
router.use('/code', authenticateAccessToken, codeRouter)
|
router.use('/code', authenticateAccessToken, codeRouter)
|
||||||
router.use('/user', desktopRestrict, userRouter)
|
router.use('/user', desktopRestrict, userRouter)
|
||||||
|
|
||||||
router.use(
|
router.use(
|
||||||
'/',
|
'/',
|
||||||
swaggerUi.serve,
|
swaggerUi.serve,
|
||||||
swaggerUi.setup(undefined, {
|
swaggerUi.setup(undefined, {
|
||||||
swaggerOptions: {
|
swaggerOptions: {
|
||||||
url: '/swagger.yaml'
|
url: '/swagger.yaml',
|
||||||
|
requestInterceptor: (request: any) => {
|
||||||
|
request.credentials = 'include'
|
||||||
|
|
||||||
|
const cookie = document.cookie
|
||||||
|
const startIndex = cookie.indexOf('XSRF-TOKEN')
|
||||||
|
const csrf = cookie.slice(startIndex + 11).split('; ')[0]
|
||||||
|
request.headers['X-XSRF-TOKEN'] = csrf
|
||||||
|
return request
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,27 +1,23 @@
|
|||||||
import path from 'path'
|
|
||||||
import express from 'express'
|
import express from 'express'
|
||||||
import { fileExists } from '@sasjs/utils'
|
|
||||||
import { WebController } from '../../controllers/web'
|
import { WebController } from '../../controllers/web'
|
||||||
import { getWebBuildFolderPath, loginWebValidation } from '../../utils'
|
import { loginWebValidation } from '../../utils'
|
||||||
|
|
||||||
const webRouter = express.Router()
|
const webRouter = express.Router()
|
||||||
|
const controller = new WebController()
|
||||||
|
|
||||||
webRouter.get('/', async (req, res) => {
|
webRouter.get('/', async (req, res) => {
|
||||||
const indexHtmlPath = path.join(getWebBuildFolderPath(), 'index.html')
|
try {
|
||||||
|
const response = await controller.home(req)
|
||||||
if (await fileExists(indexHtmlPath)) {
|
return res.send(response)
|
||||||
res.cookie('XSRF-TOKEN', req.csrfToken())
|
} catch (_) {
|
||||||
return res.sendFile(indexHtmlPath)
|
return res.send('Web Build is not present')
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.send('Web Build is not present')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
webRouter.post('/login', async (req, res) => {
|
webRouter.post('/login', async (req, res) => {
|
||||||
const { error, value: body } = loginWebValidation(req.body)
|
const { error, value: body } = loginWebValidation(req.body)
|
||||||
if (error) return res.status(400).send(error.details[0].message)
|
if (error) return res.status(400).send(error.details[0].message)
|
||||||
|
|
||||||
const controller = new WebController()
|
|
||||||
try {
|
try {
|
||||||
const response = await controller.login(req, body)
|
const response = await controller.login(req, body)
|
||||||
res.send(response)
|
res.send(response)
|
||||||
@@ -31,10 +27,9 @@ webRouter.post('/login', async (req, res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
webRouter.get('/logout', async (req, res) => {
|
webRouter.get('/logout', async (req, res) => {
|
||||||
const controller = new WebController()
|
|
||||||
try {
|
try {
|
||||||
await controller.logout(req)
|
await controller.logout(req)
|
||||||
res.status(200).send()
|
res.status(200).send('OK!')
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
res.status(400).send(err.toString())
|
res.status(400).send(err.toString())
|
||||||
}
|
}
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.60",
|
"version": "0.0.68",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.60",
|
"version": "0.0.68",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.3.1",
|
"prettier": "^2.3.1",
|
||||||
"standard-version": "^9.3.2"
|
"standard-version": "^9.3.2"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "0.0.60",
|
"version": "0.0.68",
|
||||||
"description": "NodeJS wrapper for calling the SAS binary executable",
|
"description": "NodeJS wrapper for calling the SAS binary executable",
|
||||||
"repository": "https://github.com/sasjs/server",
|
"repository": "https://github.com/sasjs/server",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
370
web/package-lock.json
generated
370
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/react": "^11.4.1",
|
"@emotion/react": "^11.4.1",
|
||||||
"@emotion/styled": "^11.3.0",
|
"@emotion/styled": "^11.3.0",
|
||||||
"@monaco-editor/react": "^4.3.1",
|
|
||||||
"@mui/icons-material": "^5.0.3",
|
"@mui/icons-material": "^5.0.3",
|
||||||
"@mui/lab": "^5.0.0-alpha.50",
|
"@mui/lab": "^5.0.0-alpha.50",
|
||||||
"@mui/material": "^5.0.3",
|
"@mui/material": "^5.0.3",
|
||||||
@@ -21,8 +20,10 @@
|
|||||||
"@types/node": "^12.20.28",
|
"@types/node": "^12.20.28",
|
||||||
"@types/react": "^17.0.27",
|
"@types/react": "^17.0.27",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
|
"monaco-editor-webpack-plugin": "^7.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
"react-monaco-editor": "^0.48.0",
|
||||||
"react-router-dom": "^5.3.0"
|
"react-router-dom": "^5.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'
|
|||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
import Editor from '@monaco-editor/react'
|
import Editor from 'react-monaco-editor'
|
||||||
|
|
||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
import Paper from '@mui/material/Paper'
|
import Paper from '@mui/material/Paper'
|
||||||
@@ -125,6 +125,7 @@ const Main = (props: Props) => {
|
|||||||
{!isLoading && props?.selectedFilePath && editMode && (
|
{!isLoading && props?.selectedFilePath && editMode && (
|
||||||
<Editor
|
<Editor
|
||||||
height="95%"
|
height="95%"
|
||||||
|
language="sas"
|
||||||
value={fileContent}
|
value={fileContent}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
if (val) setFileContent(val)
|
if (val) setFileContent(val)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import axios from 'axios'
|
|||||||
import Box from '@mui/material/Box'
|
import Box from '@mui/material/Box'
|
||||||
import { Button, Paper, Stack, Tab, Tooltip } from '@mui/material'
|
import { Button, Paper, Stack, Tab, Tooltip } from '@mui/material'
|
||||||
import { makeStyles } from '@mui/styles'
|
import { makeStyles } from '@mui/styles'
|
||||||
import Editor, { OnMount } from '@monaco-editor/react'
|
import Editor, { EditorDidMount } from 'react-monaco-editor'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation } from 'react-router-dom'
|
||||||
import { TabContext, TabList, TabPanel } from '@mui/lab'
|
import { TabContext, TabList, TabPanel } from '@mui/lab'
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ const Studio = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const editorRef = useRef(null as any)
|
const editorRef = useRef(null as any)
|
||||||
const handleEditorDidMount: OnMount = (editor) => {
|
const handleEditorDidMount: EditorDidMount = (editor) => {
|
||||||
editor.focus()
|
editor.focus()
|
||||||
editorRef.current = editor
|
editorRef.current = editor
|
||||||
}
|
}
|
||||||
@@ -141,6 +141,7 @@ const Studio = () => {
|
|||||||
<Tooltip title="CTRL+ENTER will also run SAS code">
|
<Tooltip title="CTRL+ENTER will also run SAS code">
|
||||||
<Button onClick={handleRunBtnClick} className={classes.runButton}>
|
<Button onClick={handleRunBtnClick} className={classes.runButton}>
|
||||||
<img
|
<img
|
||||||
|
alt=""
|
||||||
draggable="false"
|
draggable="false"
|
||||||
style={{ width: '25px' }}
|
style={{ width: '25px' }}
|
||||||
src="/running-sas.png"
|
src="/running-sas.png"
|
||||||
@@ -161,8 +162,9 @@ const Studio = () => {
|
|||||||
>
|
>
|
||||||
<Editor
|
<Editor
|
||||||
height="98%"
|
height="98%"
|
||||||
|
language="sas"
|
||||||
value={fileContent}
|
value={fileContent}
|
||||||
onMount={handleEditorDidMount}
|
editorDidMount={handleEditorDidMount}
|
||||||
options={{ readOnly: ctrlPressed }}
|
options={{ readOnly: ctrlPressed }}
|
||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
if (val) setFileContent(val)
|
if (val) setFileContent(val)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin'
|
||||||
import { Configuration } from 'webpack'
|
import { Configuration } from 'webpack'
|
||||||
import HtmlWebpackPlugin from 'html-webpack-plugin'
|
import HtmlWebpackPlugin from 'html-webpack-plugin'
|
||||||
import CopyPlugin from 'copy-webpack-plugin'
|
import CopyPlugin from 'copy-webpack-plugin'
|
||||||
@@ -53,7 +54,8 @@ const config: Configuration = {
|
|||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [{ from: 'public' }]
|
patterns: [{ from: 'public' }]
|
||||||
}),
|
}),
|
||||||
new dotenv()
|
new dotenv(),
|
||||||
|
new MonacoWebpackPlugin()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user