1st commit
This commit is contained in:
commit
159683d7ba
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
.vscode
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "ui"]
|
||||
path = ui
|
||||
url = https://github.com/mydraft-cc/ui.git
|
1
.prettierignore
Normal file
1
.prettierignore
Normal file
@ -0,0 +1 @@
|
||||
ui/*
|
10
package.json
Normal file
10
package.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "mydraftcc-nodejs-server",
|
||||
"version": "1.0.0",
|
||||
"description": "NodeJs Server For mydraftcc/ui",
|
||||
"scripts": {
|
||||
"populatepublicserver": "rsync -ravH ui/build/* server/public/"
|
||||
},
|
||||
"author": "damien HENRY - https://www.mytinydc.com",
|
||||
"license": "MIT Licence"
|
||||
}
|
49
patch.sh
Executable file
49
patch.sh
Executable file
@ -0,0 +1,49 @@
|
||||
#!/bin/bash
|
||||
|
||||
###############
|
||||
## D.HENRY (https://www.mytindydc.com)
|
||||
# Patchs are apply to be API nodejs compliant
|
||||
# UserReport because i don't want third party in the running app
|
||||
################################
|
||||
|
||||
echo "[INFO]Starting applying patchs..."
|
||||
|
||||
## Usefull for nodejs-server
|
||||
match="(const API_URL.*)(https:\/\/api.mydraft.cc)(.*)$"
|
||||
file="ui/src/wireframes/model/actions/loading.ts"
|
||||
echo "[Patching]$match-$file"
|
||||
# i replace https://api.mydraft.cc with ''
|
||||
sed -i -E "s,$match,\1\3," "$file"
|
||||
echo " [INFO]done"
|
||||
|
||||
## Usefull for nodejs-server
|
||||
echo "[Patching]Replacing load route / with /get"
|
||||
sed -i 's,${API_URL}/${args.tokenToRead},${API_URL}/get/${args.tokenToRead},' "$file"
|
||||
if [ "$?" != "0" ];then exit 1;fi
|
||||
|
||||
echo " [INFO]done"
|
||||
|
||||
## Usefull for nodejs-server
|
||||
## ContentType ERR Content-Type and application/json (needed for express body-parser)
|
||||
echo "[Patching]ContentType-application/json"
|
||||
sed -i -E "s,ContentType.*text\/json(.*)$,'Content-Type': 'application\/json\1," "$file"
|
||||
if [ "$?" != "0" ];then exit 1;fi
|
||||
echo " [INFO]done"
|
||||
|
||||
## Usefull for ... me :)
|
||||
echo "[Patching]Removing UserReport from application"
|
||||
## Remove UserReport support
|
||||
if [ -f "ui/src/core/react/UserReport.tsx" ];then
|
||||
rm -r ui/src/core/react/UserReport.tsx
|
||||
if [ "$?" != "0" ];then exit 1;fi
|
||||
fi
|
||||
## Patch tsx
|
||||
files=$(grep -r "UserReport" ui/src | awk -F ":" '{print $1}' |uniq |xargs)
|
||||
for f in $files
|
||||
do
|
||||
echo " [INFO]Patching UserReport in $f"
|
||||
sed -i -E 's/.*UserReport.*//' "$f"
|
||||
if [ "$?" != "0" ];then exit 1;fi
|
||||
done
|
||||
echo " [INFO]done"
|
||||
|
24
server/.gitignore
vendored
Normal file
24
server/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
/data/*
|
||||
/logs/*
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
/logs/*
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
9
server/README.md
Normal file
9
server/README.md
Normal file
@ -0,0 +1,9 @@
|
||||
# minimalist Nodejs server for mydraft application (https:/mydraft.cc)
|
||||
|
||||
## Swagger
|
||||
|
||||
## Installation (Docker)
|
||||
|
||||
## Execute
|
||||
|
||||
pay **ATTENTION**
|
138
server/app.js
Normal file
138
server/app.js
Normal file
@ -0,0 +1,138 @@
|
||||
require("include-path")(["./lib"]);
|
||||
const express = require("express");
|
||||
//to parser body as json fetch must have parameter
|
||||
//headers: {
|
||||
// 'Content-Type': 'application/json',
|
||||
//},
|
||||
const bodyParser = require("body-parser");
|
||||
const path = require("path");
|
||||
const cookieParser = require("cookie-parser");
|
||||
const http = require("http");
|
||||
//Helpers
|
||||
const HelperXhr = require("HelperXhr");
|
||||
//Logs nodejs
|
||||
//--> http: morgan
|
||||
const morgan = require("morgan");
|
||||
const logger = require("logger");
|
||||
//cors
|
||||
const cors = require("cors");
|
||||
//framework express
|
||||
const app = express();
|
||||
//Body parser
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
app.use(bodyParser.json());
|
||||
|
||||
//API routes
|
||||
const routes = require("./routes.js");
|
||||
|
||||
//Swagger UI
|
||||
const swaggerUi = require("swagger-ui-express");
|
||||
const YAML = require("yamljs");
|
||||
const swaggerDocumentCore = YAML.load("./openapi.yaml");
|
||||
const swaggeroptions = {
|
||||
explorer: true,
|
||||
};
|
||||
|
||||
//cors options - no options
|
||||
app.use(cors({}));
|
||||
|
||||
/**
|
||||
* explainations : https://dev.to/p0oker/why-is-my-browser-sending-an-options-http-request-instead-of-post-5621
|
||||
*/
|
||||
app.use(function (req, res, next) {
|
||||
res.header("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
|
||||
res.header(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Content-Type, InstantKey, Content-Length, X-Requested-With"
|
||||
);
|
||||
//OPTIONS methods interception
|
||||
if ("OPTIONS" === req.method) {
|
||||
res.sendStatus(200);
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
// listening port server
|
||||
app.set("PORT", process.env.PORT || "4000");
|
||||
// listening IP address server
|
||||
app.set("IPADDRESS", process.env.IPADDRESS || "0.0.0.0");
|
||||
// Max size allowed to upload Json files (Default is 2Mo)
|
||||
app.set("JSONMAXSIZE", process.env.JSONMAXSIZE || 2 * 1024 * 1024);
|
||||
|
||||
//logger become global to controller via req.app.get('logger')
|
||||
app.set("logger", logger);
|
||||
|
||||
//Application logs - format see wiki about morgan logs
|
||||
let loghttpformat = "combined";
|
||||
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({ extended: false }));
|
||||
app.use(cookieParser());
|
||||
app.use(express.static(path.join(__dirname, "public")));
|
||||
|
||||
//set log http
|
||||
app.use(morgan(loghttpformat));
|
||||
|
||||
// Routes
|
||||
try {
|
||||
// route / load public content
|
||||
app.use("/", express.static(path.join(__dirname, "public")));
|
||||
// route /api-docs load Swagger UI
|
||||
app.use(
|
||||
"/api-docs",
|
||||
swaggerUi.serve,
|
||||
swaggerUi.setup(swaggerDocumentCore, swaggeroptions)
|
||||
);
|
||||
// route /xxx-xxx-xxxx where xxx-xxx-xxx is a diagram Id
|
||||
app.use(
|
||||
"/:diagramId",
|
||||
express.static(path.join(__dirname, "public", "index.html"))
|
||||
);
|
||||
// API Routes
|
||||
app.use(routes);
|
||||
} catch (err) {
|
||||
// logger.error(err.toString(), err);
|
||||
logger.error(err.toString(), err);
|
||||
}
|
||||
|
||||
// resource not found - 404 and forward to error handler
|
||||
app.use(function (req, res, next) {
|
||||
console.log("Resource is missing");
|
||||
req.statusCode = 404;
|
||||
next(new Error(), req, res);
|
||||
});
|
||||
|
||||
// Global error handler
|
||||
app.use(function (err, req, res, next) {
|
||||
let statuscode = req.statusCode; //404 received ???
|
||||
if (!statuscode) statuscode = 500;
|
||||
if (statuscode !== 404) {
|
||||
logger.error(err.toString(), err);
|
||||
message = "Internal Error - see logs";
|
||||
} else {
|
||||
message = "404-Resource Not Found";
|
||||
}
|
||||
if (HelperXhr.isXhrRequest(req)) {
|
||||
res.status(statuscode).json({ error: message });
|
||||
} else {
|
||||
res.status(statuscode).send("<html><h1>" + message + "</h1></html>");
|
||||
}
|
||||
});
|
||||
|
||||
const httpServer = http.createServer(app);
|
||||
|
||||
//catch httpServer Errors type uncaughtException :EADDRNOTAVAIL EADDRINUSE
|
||||
process.on("uncaughtException", function (err) {
|
||||
logger.error(err.toString(), err);
|
||||
});
|
||||
|
||||
//start server
|
||||
httpServer.listen(app.get("PORT"), app.get("IPADDRESS"), function () {
|
||||
logger.info({
|
||||
listeningonipaddress: app.get("IPADDRESS"),
|
||||
listeningonport: app.get("PORT"),
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = app;
|
55
server/lib/HelperXhr.js
Normal file
55
server/lib/HelperXhr.js
Normal file
@ -0,0 +1,55 @@
|
||||
"use strict";
|
||||
const Libsecurity = require("Libsecurity");
|
||||
|
||||
class HelperXhr {
|
||||
/**
|
||||
* Return req.xhr state to determine if request is xhr type
|
||||
* @param {object} req - req Express var
|
||||
* @return {boolean}
|
||||
*/
|
||||
static isXhrRequest(req) {
|
||||
if (req && req.headers && req.headers.accept) {
|
||||
return req.headers.accept.indexOf("json") > -1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Push received Data on object
|
||||
* @return object
|
||||
*/
|
||||
static setSettings(req) {
|
||||
let obj = {};
|
||||
console.log(req);
|
||||
try {
|
||||
if (req.method.match(/POST|PUT/i)) {
|
||||
obj = Object.keys(req.body).length > 0 ? req.body : {};
|
||||
} else if (req.method.match(/GET/i)) {
|
||||
//no body with GET method !! use query.data
|
||||
obj = req.query && req.query.data ? JSON.parse(req.query.data) : {};
|
||||
} else {
|
||||
throw new Error(
|
||||
"HelperXhr::setSettings-req.method not supported-" + req.method
|
||||
);
|
||||
}
|
||||
// // Parsing req.body API receive only json so string is JSON
|
||||
// if (typeof obj === "string") {
|
||||
// obj = JSON.parse(obj);
|
||||
// }
|
||||
//check size
|
||||
if (typeof obj === "object") {
|
||||
Libsecurity.jsonSizeIsAcceptable(obj, req.app.get("JSONMAXSIZE"));
|
||||
}
|
||||
//url paramèters are also put in object
|
||||
if (req.params && typeof req.params === "object") {
|
||||
for (let param in req.params) {
|
||||
obj[param] = req.params[param];
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
} catch (error) {
|
||||
//if called from controller to call express error handler
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
module.exports = HelperXhr;
|
36
server/lib/Libsecurity.js
Normal file
36
server/lib/Libsecurity.js
Normal file
@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
class Libsecurity {
|
||||
/**
|
||||
*
|
||||
* @param {object} obj
|
||||
* @param {number} maxsize
|
||||
* @returns
|
||||
*/
|
||||
static jsonSizeIsAcceptable(obj, maxsize) {
|
||||
const size = JSON.stringify(obj).length;
|
||||
if (typeof obj === "object" && size > maxsize)
|
||||
throw new Error(
|
||||
"Warning Date received exceed defined max size - Libsecurity",
|
||||
"size received:",
|
||||
obj.length,
|
||||
"acceptable",
|
||||
size
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} str - filename to sanitize
|
||||
* @returns
|
||||
*/
|
||||
static sanitizeFileName(str) {
|
||||
return str
|
||||
.replace(/(.*\/)|(\/.*)/g, "")
|
||||
.replace(/\.\./g, "")
|
||||
.replace(/;/g, "");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Libsecurity;
|
47
server/lib/logger.js
Normal file
47
server/lib/logger.js
Normal file
@ -0,0 +1,47 @@
|
||||
const { createLogger, format, transports, config } = require("winston");
|
||||
|
||||
//exception log filename
|
||||
const exceptionlogfile = __dirname + "/../logs/exceptions.log";
|
||||
const rejectionslogfile = __dirname + "/../logs/rejections.log";
|
||||
const errorslogfile = __dirname + "/../logs/errors.log";
|
||||
const debugslogfile = __dirname + "/../logs/debug.log";
|
||||
|
||||
/**
|
||||
* Levels winston
|
||||
* {
|
||||
error: 0,
|
||||
warn: 1,
|
||||
info: 2,
|
||||
http: 3,
|
||||
verbose: 4,
|
||||
debug: 5,
|
||||
silly: 6
|
||||
}
|
||||
*/
|
||||
const logger = createLogger({
|
||||
transports: [
|
||||
new transports.Console({
|
||||
level: "info",
|
||||
format: format.combine(
|
||||
// format.colorize(),
|
||||
format.timestamp(),
|
||||
format.json()
|
||||
),
|
||||
}),
|
||||
new transports.File({
|
||||
level: "error",
|
||||
format: format.combine(format.timestamp(), format.json()),
|
||||
filename: errorslogfile,
|
||||
}),
|
||||
new transports.File({
|
||||
level: "debug",
|
||||
format: format.combine(format.timestamp(), format.json()),
|
||||
filename: debugslogfile,
|
||||
}),
|
||||
],
|
||||
exceptionHandlers: [new transports.File({ filename: exceptionlogfile })],
|
||||
rejectionHandlers: [new transports.File({ filename: rejectionslogfile })],
|
||||
//see winston documentation https://www.npmjs.com/package/winston#logging-levels
|
||||
exitOnError: false,
|
||||
});
|
||||
module.exports = logger;
|
167
server/openapi.yaml
Normal file
167
server/openapi.yaml
Normal file
@ -0,0 +1,167 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
version: 3.0.0
|
||||
description: "Nodejs API server for https://mydraft.cc - UI"
|
||||
title: "Mydraft Nodejs server"
|
||||
contact:
|
||||
website: www.mytinydc.com
|
||||
license:
|
||||
name: "MIT Licence"
|
||||
url: "https://mit-license.org/"
|
||||
|
||||
tags:
|
||||
- name: "manage"
|
||||
description: "Load/Save draft"
|
||||
|
||||
servers:
|
||||
- url: 'http://localhost:4000'
|
||||
|
||||
components:
|
||||
schemas:
|
||||
serverresponsestore:
|
||||
type: object
|
||||
properties:
|
||||
writeToken:
|
||||
type: string
|
||||
readToken:
|
||||
type: string
|
||||
|
||||
internalerror:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
|
||||
diagrammestructure:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
|
||||
paths:
|
||||
/:
|
||||
post:
|
||||
tags:
|
||||
- "manage"
|
||||
summary: "Store new draft document"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/diagrammestructure'
|
||||
examples:
|
||||
JsonOK:
|
||||
value: [{"type":"diagram/add","payload":{"diagramId":"f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a","timestamp":1654256184083}},{"type":"items/addVisual","payload":{"diagramId":"f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a","timestamp":1654256186400,"shapeId":"82170ec5-2cc5-c0f2-1414-38e8e477dd01","renderer":"Button","position":{"x":199.5,"y":119.30000305175781}}}]
|
||||
badFormat:
|
||||
value: 'This is not JSON format'
|
||||
responses:
|
||||
"200":
|
||||
description: "successful operation"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/serverresponsestore'
|
||||
|
||||
"500":
|
||||
description: "Server Internal ERROR"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/internalerror'
|
||||
security: [] # no authentication
|
||||
|
||||
/{tokenToRead}/{tokenToWrite}:
|
||||
put:
|
||||
tags:
|
||||
- "manage"
|
||||
summary: "Update draft document"
|
||||
parameters:
|
||||
- name: "tokenToRead"
|
||||
in: "path"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
GoodId:
|
||||
value: 'f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a'
|
||||
WronId:
|
||||
value: 'not the good id'
|
||||
- name: "tokenToWrite"
|
||||
in: "path"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
GoodId:
|
||||
value: 'f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a'
|
||||
WronId:
|
||||
value: 'not the good id'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/diagrammestructure'
|
||||
examples:
|
||||
JsonOK:
|
||||
value: [{"type":"diagram/add","payload":{"diagramId":"f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a","timestamp":1654256184083}},{"type":"items/addVisual","payload":{"diagramId":"f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a","timestamp":1654256186400,"shapeId":"82170ec5-2cc5-c0f2-1414-38e8e477dd01","renderer":"Button","position":{"x":199.5,"y":119.30000305175781}}}]
|
||||
badFormat:
|
||||
value: 'This is not JSON format'
|
||||
responses:
|
||||
"200":
|
||||
description: "successful operation"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/serverresponsestore'
|
||||
"400":
|
||||
description: "probleme with body content JSON structure"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/internalerror'
|
||||
"500":
|
||||
description: "Server Internal ERROR"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/internalerror'
|
||||
security: [] # no authentication
|
||||
|
||||
/get/{diagramID}:
|
||||
get:
|
||||
tags:
|
||||
- "manage"
|
||||
summary: "return JSON Object"
|
||||
parameters:
|
||||
- name: "diagramID"
|
||||
in: "path"
|
||||
description: "diagramme ID"
|
||||
required: true
|
||||
schema:
|
||||
type: "string"
|
||||
examples:
|
||||
GoodId:
|
||||
value: 'f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a'
|
||||
WronId:
|
||||
value: 'not the good id'
|
||||
RunDir:
|
||||
value: '../f9e48fc9-da3d-aa39-1ab5-0641b0a0f59a'
|
||||
responses:
|
||||
"200":
|
||||
description: "successful operation"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/diagrammestructure'
|
||||
"500":
|
||||
description: "Server Internal ERROR"
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/internalerror'
|
||||
security: [] # no authentication
|
||||
|
||||
|
||||
|
||||
|
2493
server/package-lock.json
generated
Normal file
2493
server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
29
server/package.json
Normal file
29
server/package.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "mydraftcc-nodejs-server",
|
||||
"version": "1.0.0",
|
||||
"description": "built by https://wwww.mytinydc.com - Mydraftcc - NodesJs server",
|
||||
"author": "Damien HENRY - https://www.mytinydc.com",
|
||||
"license": "MIT License",
|
||||
"main": "app.js",
|
||||
"directories": {
|
||||
"lib": "lib"
|
||||
},
|
||||
"scripts": {
|
||||
"debug-startserver": "IPADDRESS=0.0.0.0 PORT=4000 JSONMAXSIZE=2097152 nodemon -w ./ app.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.21.4",
|
||||
"body-parser": "^1.20.0",
|
||||
"cookie-parser": "~1.4.4",
|
||||
"cors": "^2.8.5",
|
||||
"ejs": "^3.1.7",
|
||||
"express": "~4.17.1",
|
||||
"express-session": "^1.17.1",
|
||||
"http-errors": "~1.6.3",
|
||||
"include-path": "^0.4.7",
|
||||
"morgan": "~1.9.1",
|
||||
"swagger-ui-express": "^4.4.0",
|
||||
"winston": "^3.3.3",
|
||||
"yamljs": "^0.3.0"
|
||||
}
|
||||
}
|
95
server/routes.js
Normal file
95
server/routes.js
Normal file
@ -0,0 +1,95 @@
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Not use logger here use try catch and next(Error) in catch bloc to call the global error handler
|
||||
*/
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const HelperXhr = require("HelperXhr");
|
||||
const Libsecurity = require("Libsecurity");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
//Dir storage
|
||||
const datadir = __dirname + "/data";
|
||||
let response = "";
|
||||
let codestatus = 500;
|
||||
|
||||
/**
|
||||
* see swagger model
|
||||
* Store json file
|
||||
*/
|
||||
router.post("/", async function (req, res, next) {
|
||||
try {
|
||||
//check data received
|
||||
let xhr = HelperXhr.setSettings(req);
|
||||
console.log(xhr);
|
||||
if (Array.isArray(xhr) && xhr[0].payload.diagramId) {
|
||||
const id = xhr[0].payload.diagramId;
|
||||
if (id) {
|
||||
if (fs.existsSync(datadir)) {
|
||||
fs.writeFileSync(datadir + "/" + id, JSON.stringify(xhr));
|
||||
codestatus = 200;
|
||||
response = { writeToken: id, readToken: id };
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Json structure is wrong");
|
||||
}
|
||||
res.status(codestatus).json(response);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* see swagger model
|
||||
*/
|
||||
router.put("/:tokenWrite/:tokenRead", async function (req, res, next) {
|
||||
try {
|
||||
const tokenWrite = req.params.tokenWrite;
|
||||
const tokenRead = req.params.tokenRead;
|
||||
//check data received
|
||||
let xhr = HelperXhr.setSettings(req);
|
||||
|
||||
if (
|
||||
Array.isArray(xhr) &&
|
||||
xhr[0] &&
|
||||
xhr[0].payload &&
|
||||
xhr[0].payload.diagramId &&
|
||||
tokenWrite &&
|
||||
tokenWrite === tokenRead &&
|
||||
tokenWrite === xhr[0].payload.diagramId
|
||||
) {
|
||||
const id = xhr[0].payload.diagramId;
|
||||
if (id) {
|
||||
fs.writeFileSync(datadir + "/" + id, JSON.stringify(xhr));
|
||||
codestatus = 200;
|
||||
response = { writeToken: id, readToken: id };
|
||||
}
|
||||
} else {
|
||||
throw new Error("Json structure is wrong");
|
||||
}
|
||||
res.status(codestatus).json(response);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 2 cases
|
||||
* - isXhr request return json
|
||||
* - else public/index.html
|
||||
*/
|
||||
router.get("/get/:diagramId", function (req, res, next) {
|
||||
try {
|
||||
const id = Libsecurity.sanitizeFileName(req.params.diagramId);
|
||||
response = JSON.parse(fs.readFileSync(datadir + "/" + id, "utf8"));
|
||||
codestatus = 200;
|
||||
res.status(codestatus).json(response);
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
382
webpack.config.js-forlocaldeveloppementwithserver
Normal file
382
webpack.config.js-forlocaldeveloppementwithserver
Normal file
@ -0,0 +1,382 @@
|
||||
/* eslint-disable prefer-spread */
|
||||
/* eslint-disable prefer-rest-params */
|
||||
/* eslint-disable global-require */
|
||||
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
|
||||
const appRoot = path.resolve(__dirname, '..');
|
||||
|
||||
function root() {
|
||||
const newArgs = Array.prototype.slice.call(arguments, 0);
|
||||
|
||||
return path.join.apply(path, [appRoot].concat(newArgs));
|
||||
}
|
||||
|
||||
const plugins = {
|
||||
// https://github.com/webpack-contrib/mini-css-extract-plugin
|
||||
MiniCssExtractPlugin: require('mini-css-extract-plugin'),
|
||||
// https://github.com/dividab/tsconfig-paths-webpack-plugin
|
||||
TsconfigPathsPlugin: require('tsconfig-paths-webpack-plugin'),
|
||||
// https://github.com/aackerman/circular-dependency-plugin
|
||||
CircularDependencyPlugin: require('circular-dependency-plugin'),
|
||||
// https://github.com/jantimon/html-webpack-plugin
|
||||
HtmlWebpackPlugin: require('html-webpack-plugin'),
|
||||
// https://webpack.js.org/plugins/terser-webpack-plugin/
|
||||
TerserPlugin: require('terser-webpack-plugin'),
|
||||
// https://github.com/NMFR/optimize-css-assets-webpack-plugin
|
||||
CssMinimizerPlugin: require('css-minimizer-webpack-plugin'),
|
||||
// https://webpack.js.org/plugins/eslint-webpack-plugin/
|
||||
ESLintPlugin: require('eslint-webpack-plugin'),
|
||||
// https://github.com/webpack-contrib/stylelint-webpack-plugin
|
||||
StylelintPlugin: require('stylelint-webpack-plugin'),
|
||||
// https://www.npmjs.com/package/webpack-bundle-analyzer
|
||||
BundleAnalyzerPlugin: require('webpack-bundle-analyzer').BundleAnalyzerPlugin,
|
||||
// https://github.com/jantimon/favicons-webpack-plugin
|
||||
FaviconsWebpackPlugin: require('favicons-webpack-plugin'),
|
||||
// https://github.com/GoogleChrome/workbox/tree/master/packages/workbox-webpack-plugin
|
||||
GenerateSW: require('workbox-webpack-plugin').GenerateSW,
|
||||
};
|
||||
|
||||
module.exports = function configure(env) {
|
||||
const isProduction = env && env.production;
|
||||
const isTests = env && env.target === 'tests';
|
||||
const isTestCoverage = env && env.coverage;
|
||||
const isAnalyzing = isProduction && env.analyze;
|
||||
|
||||
const config = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
|
||||
/**
|
||||
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/devtool/
|
||||
*/
|
||||
devtool: isProduction ? false : 'inline-source-map',
|
||||
|
||||
/**
|
||||
* Options affecting the resolving of modules.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/resolve/
|
||||
*/
|
||||
resolve: {
|
||||
/**
|
||||
* An array of extensions that should be used to resolve modules.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/resolve/#resolve-extensions
|
||||
*/
|
||||
extensions: ['.ts', '.tsx', '.js', '.mjs', '.css', '.scss'],
|
||||
modules: [
|
||||
root('src'),
|
||||
root('src', 'style'),
|
||||
root('node_modules'),
|
||||
],
|
||||
|
||||
plugins: [
|
||||
new plugins.TsconfigPathsPlugin({
|
||||
configFile: 'tsconfig.json',
|
||||
}),
|
||||
],
|
||||
},
|
||||
|
||||
/**
|
||||
* Options affecting the normal modules.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/module/
|
||||
*/
|
||||
module: {
|
||||
/**
|
||||
* An array of Rules which are matched to requests when modules are created.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/module/#module-rules
|
||||
*/
|
||||
rules: [{
|
||||
test: /\.html$/,
|
||||
use: [{
|
||||
loader: 'raw-loader',
|
||||
}],
|
||||
}, {
|
||||
test: /\.d\.ts?$/,
|
||||
use: [{
|
||||
loader: 'ignore-loader',
|
||||
}],
|
||||
include: [/node_modules/],
|
||||
}, {
|
||||
test: /\.(png|jpe?g|gif|svg|ico)(\?.*$|$)/,
|
||||
use: [{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[contenthash].[ext]',
|
||||
|
||||
// Store the assets in custom path because of fonts need relative urls.
|
||||
outputPath: 'assets',
|
||||
},
|
||||
}],
|
||||
}, {
|
||||
test: /\.css$/,
|
||||
use: [{
|
||||
loader: plugins.MiniCssExtractPlugin.loader,
|
||||
}, {
|
||||
loader: 'css-loader',
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
}],
|
||||
}],
|
||||
},
|
||||
|
||||
plugins: [
|
||||
/**
|
||||
* Puts each bundle into a file without the hash.
|
||||
*
|
||||
* See: https://github.com/webpack-contrib/mini-css-extract-plugin
|
||||
*/
|
||||
new plugins.MiniCssExtractPlugin({
|
||||
filename: '[name].css',
|
||||
}),
|
||||
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
options: {
|
||||
htmlLoader: {
|
||||
/**
|
||||
* Define the root for images, so that we can use absolute urls.
|
||||
*
|
||||
* See: https://github.com/webpack/html-loader#Advanced_Options
|
||||
*/
|
||||
root: root('src', 'images'),
|
||||
},
|
||||
context: '/',
|
||||
},
|
||||
}),
|
||||
|
||||
new plugins.FaviconsWebpackPlugin({
|
||||
// Favicon source logo
|
||||
logo: 'src/images/logo-square.png',
|
||||
// Favicon app title
|
||||
title: 'MyDraft',
|
||||
favicons: {
|
||||
appName: 'mydraft.cc',
|
||||
appDescription: 'Open Source Wireframe Editor',
|
||||
developerName: 'Sebastian Stehle',
|
||||
developerUrl: 'https://sstehle.com',
|
||||
start_url: '/',
|
||||
},
|
||||
}),
|
||||
|
||||
new plugins.StylelintPlugin({
|
||||
files: '**/*.scss',
|
||||
}),
|
||||
|
||||
/**
|
||||
* Detect circular dependencies in app.
|
||||
*
|
||||
* See: https://github.com/aackerman/circular-dependency-plugin
|
||||
*/
|
||||
new plugins.CircularDependencyPlugin({
|
||||
exclude: /([\\/]node_modules[\\/])/,
|
||||
// Add errors to webpack instead of warnings
|
||||
failOnError: true,
|
||||
}),
|
||||
],
|
||||
|
||||
devServer: {
|
||||
headers: {
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
},
|
||||
historyApiFallback: true,
|
||||
proxy: {
|
||||
context: () => true,
|
||||
target: "http://localhost:4000",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (!isTests) {
|
||||
/**
|
||||
* The entry point for the bundle. Our React app.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/entry-context/
|
||||
*/
|
||||
config.entry = {
|
||||
src: './src/index.tsx',
|
||||
};
|
||||
|
||||
if (isProduction) {
|
||||
config.output = {
|
||||
/**
|
||||
* The output directory as absolute path (required).
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/output/#output-path
|
||||
*/
|
||||
path: root('/build/'),
|
||||
|
||||
publicPath: './',
|
||||
|
||||
/**
|
||||
* Specifies the name of each output file on disk.
|
||||
*
|
||||
* Do NOT append hash to service worker in development mode, so we can load them directly.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/output/#output-filename
|
||||
*/
|
||||
filename: (pathData) => {
|
||||
return pathData.chunk.name === 'src' ? '[name].[contenthash:8].js' : '[name].js';
|
||||
},
|
||||
|
||||
/**
|
||||
* The filename of non-entry chunks as relative path inside the output.path directory.
|
||||
*
|
||||
* See: https://webpack.js.org/configuration/output/#output-chunkfilename
|
||||
*/
|
||||
chunkFilename: '[id].[contenthash].chunk.js',
|
||||
};
|
||||
} else {
|
||||
config.output = {
|
||||
filename: '[name].[contenthash].js',
|
||||
|
||||
/**
|
||||
* Set the public path, because we are running the website from another port (5000).
|
||||
*/
|
||||
publicPath: 'https://localhost:3002/',
|
||||
|
||||
/*
|
||||
* Fix a bug with webpack dev server.
|
||||
*
|
||||
* See: https://github.com/webpack-contrib/worker-loader/issues/174
|
||||
*/
|
||||
globalObject: 'this',
|
||||
};
|
||||
}
|
||||
|
||||
config.plugins.push(
|
||||
new plugins.HtmlWebpackPlugin({
|
||||
hash: true,
|
||||
chunks: ['src'],
|
||||
chunksSortMode: 'manual',
|
||||
template: 'src/index.html',
|
||||
}),
|
||||
new plugins.HtmlWebpackPlugin({
|
||||
hash: true,
|
||||
chunks: ['src'],
|
||||
chunksSortMode: 'manual',
|
||||
template: 'src/index.html',
|
||||
filename: '404.html',
|
||||
}),
|
||||
);
|
||||
|
||||
config.plugins.push(
|
||||
new plugins.ESLintPlugin({
|
||||
files: [
|
||||
'./src/**/*.ts',
|
||||
],
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (isProduction) {
|
||||
config.optimization = {
|
||||
minimizer: [
|
||||
new plugins.TerserPlugin({
|
||||
terserOptions: {
|
||||
compress: true,
|
||||
ecma: 5,
|
||||
mangle: true,
|
||||
output: {
|
||||
comments: false,
|
||||
},
|
||||
safari10: true,
|
||||
},
|
||||
extractComments: true,
|
||||
}),
|
||||
|
||||
new plugins.CssMinimizerPlugin({}),
|
||||
],
|
||||
};
|
||||
|
||||
config.performance = {
|
||||
hints: false,
|
||||
};
|
||||
}
|
||||
|
||||
if (isTestCoverage) {
|
||||
// Do not instrument tests.
|
||||
config.module.rules.push({
|
||||
test: /\.ts[x]?$/,
|
||||
use: [{
|
||||
loader: 'ts-loader',
|
||||
}],
|
||||
include: [/\.(e2e|spec)\.ts$/],
|
||||
});
|
||||
|
||||
// Use instrument loader for all normal files.
|
||||
config.module.rules.push({
|
||||
test: /\.ts[x]?$/,
|
||||
use: [{
|
||||
loader: '@jsdevtools/coverage-istanbul-loader?esModules=true',
|
||||
}, {
|
||||
loader: 'ts-loader',
|
||||
}],
|
||||
exclude: [/\.(e2e|spec)\.ts$/],
|
||||
});
|
||||
} else {
|
||||
config.module.rules.push({
|
||||
test: /\.ts[x]?$/,
|
||||
use: [{
|
||||
loader: 'ts-loader',
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
if (isProduction) {
|
||||
config.plugins.push(new plugins.GenerateSW({
|
||||
swDest: 'service-worker2.js',
|
||||
|
||||
// Do not wait for activation
|
||||
skipWaiting: true,
|
||||
|
||||
// Cache until 5MB
|
||||
maximumFileSizeToCacheInBytes: 5000000000,
|
||||
}));
|
||||
}
|
||||
|
||||
if (isProduction) {
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
/*
|
||||
* Extract the content from a bundle to a file.
|
||||
*
|
||||
* See: https://github.com/webpack-contrib/extract-text-webpack-plugin
|
||||
*/
|
||||
use: [
|
||||
plugins.MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: 'css-loader',
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
}],
|
||||
});
|
||||
} else {
|
||||
config.module.rules.push({
|
||||
test: /\.scss$/,
|
||||
use: [{
|
||||
loader: 'style-loader',
|
||||
}, {
|
||||
loader: 'css-loader',
|
||||
}, {
|
||||
loader: 'postcss-loader',
|
||||
}, {
|
||||
loader: 'sass-loader',
|
||||
options: {
|
||||
sourceMap: true,
|
||||
},
|
||||
}],
|
||||
});
|
||||
}
|
||||
|
||||
if (isAnalyzing) {
|
||||
config.plugins.push(new plugins.BundleAnalyzerPlugin());
|
||||
}
|
||||
|
||||
return config;
|
||||
};
|
Reference in New Issue
Block a user