545 lines
18 KiB
JavaScript
545 lines
18 KiB
JavaScript
const fs = require("fs-extra");
|
|
const path = require("path");
|
|
const glob = require("glob");
|
|
const dnsSync = require("dns-sync");
|
|
const mustache = require("mustache");
|
|
const jsdom = require("jsdom");
|
|
const { JSDOM } = jsdom;
|
|
const minihtml = require("html-minifier").minify;
|
|
const minijs = require("terser").minify;
|
|
const sharp = require("sharp");
|
|
const readlineSync = require("readline-sync");
|
|
const Odmdb = require("./Odmdb.js");
|
|
const conf = require(`../../../adminapi/objects/tribes/itm/adminapi.json`);
|
|
const Wwws = {};
|
|
|
|
Wwws.build = (tribeId, webapp, srcdist, options) => {
|
|
console.log(`Building ${tribeId}/objects/wwws/${webapp}/${srcdist}`);
|
|
const pathto = `../${tribeId}/objects/wwws`;
|
|
let confwww;
|
|
if (fs.existsSync(`${pathto}/itm/${webapp}.json`)) {
|
|
confwww = fs.readJSONSync(`${pathto}/itm/${webapp}.json`);
|
|
} else {
|
|
confwww = {
|
|
website: webapp,
|
|
appimgs:[],
|
|
commentappimg:"Image list in src that are used by app that must be copy into /dist",
|
|
apxtri: {
|
|
headers: {
|
|
xtrkversion: 1,
|
|
xalias: "anonymous",
|
|
xapp: webapp,
|
|
xdays: 0,
|
|
xhash: "anonymous",
|
|
xlang: "fr", // it changed in browser with wco/apx/apx.js from html lang value
|
|
xprofils: "anonymous",
|
|
xtribe: tribeId,
|
|
xuuid: "0",
|
|
},
|
|
},
|
|
pages: {},
|
|
};
|
|
}
|
|
//console.log(confwww.pages);
|
|
if (srcdist == "dist") {
|
|
fs.removeSync(`${pathto}/${webapp}/dist`);
|
|
fs.mkdirSync(`${pathto}/${webapp}/dist`);
|
|
}
|
|
let appimgs = {}; // to store any image used in all html
|
|
glob.sync(`${pathto}/${webapp}/src/*.html`).forEach(async (f) => {
|
|
// @todo parse each html and get relevant information to copy and paste to dist confwww
|
|
const pginfo = path.parse(f).name.split("_");
|
|
const lg = pginfo.pop();
|
|
const pgname = pginfo.join("_");
|
|
console.log(f, pgname);
|
|
if (!confwww.pages[pgname]) {
|
|
confwww.pages[pgname] = {
|
|
version: 1,
|
|
languages: [],
|
|
profils: ["anonymous"],
|
|
tpl: {},
|
|
tpldata: {},
|
|
itms: {},
|
|
ref: {
|
|
Checkjson: "adminapi/objects/tplstrings/Checkjson",
|
|
Notification: "adminapi/objects/tplstrings/Notifications",
|
|
Odmdb: "adminapi/objects/tplstrings/Odmdb",
|
|
Pagans: "adminapi/objects/tplstrings/Pagans",
|
|
Middlewares: "adminapi/objects/tplstrings/middlewares",
|
|
},
|
|
schema: ["adminapi/objects/pagans", `${tribeId}/objects/persons`],
|
|
options: { profil: `${tribeId}/objects/options/profil` },
|
|
wcodata: {},
|
|
appdata: {},
|
|
};
|
|
}
|
|
if (!confwww.pages[pgname].languages.includes(lg))
|
|
confwww.pages[pgname].languages.push(lg);
|
|
|
|
const pgtxt = fs.readFileSync(f, "utf8");
|
|
const pg = new JSDOM(pgtxt);
|
|
const dc = pg.window.document;
|
|
let pgscripts = [];
|
|
dc.querySelectorAll("script[src]").forEach((s) => {
|
|
if (!pgscripts.includes(s.getAttribute("src"))) {
|
|
pgscripts.push(s.getAttribute("src"));
|
|
}
|
|
});
|
|
dc.querySelectorAll("img[src]").forEach((s) => {
|
|
const imgsrc = s.getAttribute("src");
|
|
s.setAttribute(
|
|
"src",
|
|
imgsrc.replace(/(.*)\.(png|png|gif|bmp|jpg|jpeg)$/, "$1.webp")
|
|
);
|
|
if (!appimgs[imgsrc]) {
|
|
appimgs[imgsrc]={pages:[]};
|
|
}
|
|
appimgs[imgsrc].pages.push(pginfo)
|
|
});
|
|
let wcojs = "";
|
|
pgscripts.forEach((s) => {
|
|
if (s[0] !== "/" && s.substring(0, 4) != "http") {
|
|
// file must be copy to dist if / means it is absolute not relative
|
|
if (s.includes("wco/")) {
|
|
//console.log(`${pathto}/${webapp}/src/wco/${path.parse(s).name}/*.mustache`)
|
|
glob
|
|
.sync(
|
|
`${pathto}/${webapp}/src/wco/${path.parse(s).name}/*.mustache`
|
|
)
|
|
.forEach((m) => {
|
|
const tplname = path.parse(m).name.replace(/_..$/, "");
|
|
confwww.pages[pgname].tpl[
|
|
`${path.parse(s).name}${tplname}`
|
|
] = `${tribeId}/${m.replace(/_..\.mustache$/, "")}`;
|
|
});
|
|
dc.querySelectorAll(`script[src='${s}']`).forEach((e) => e.remove());
|
|
wcojs +=
|
|
fs.readFileSync(`${pathto}/${webapp}/src/${s}`, "utf8") + "\n";
|
|
} else {
|
|
if (srcdist == "dist") {
|
|
fs.copySync(
|
|
`../${tribeId}/objects/wwws/${webapp}/src/${s}`,
|
|
`../${tribeId}/objects/wwws/${webapp}/dist/${s}`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
glob
|
|
.sync(`${pathto}/${webapp}/src/tpldata/${pgname}/*.json`)
|
|
.forEach((t) => {
|
|
const tpldataname = path.parse(t).name.replace(/_..$/, "");
|
|
console.log("tpldata:",tpldataname);
|
|
confwww.pages[pgname].tpldata[tpldataname] = `${tribeId}/${t.replace(
|
|
/_..\.json$/,
|
|
""
|
|
)}`;
|
|
});
|
|
if (srcdist == "dist") {
|
|
//add last script static/js/pagenamewco.js
|
|
const swco = dc.createElement("script");
|
|
swco.src = `static/js/${pgname.replace(/_..$/, "")}wco.js`;
|
|
swco.type = "text/javascript";
|
|
dc.head.appendChild(swco);
|
|
const minijswco = await minijs(wcojs, {
|
|
compress: {
|
|
drop_console: true, // Supprime les appels console.log
|
|
passes: 2, // Effectue plusieurs passes pour optimiser davantage
|
|
},
|
|
mangle: {
|
|
toplevel: true, // Renomme les variables au niveau supérieur
|
|
},
|
|
});
|
|
fs.outputFileSync(
|
|
`${pathto}/${webapp}/dist/static/js/${pgname.replace(
|
|
/_..$/,
|
|
""
|
|
)}wco.js`,
|
|
minijswco.code,
|
|
"utf8"
|
|
);
|
|
const minipg = minihtml(pg.serialize(), {
|
|
collapseWhitespace: true,
|
|
removeComments: true,
|
|
removeRedundantAttributes: true,
|
|
minifyCSS: true,
|
|
minifyJS: true,
|
|
});
|
|
fs.outputFileSync(
|
|
`${pathto}/${webapp}/dist/${pgname}_${lg}.html`,
|
|
minipg,
|
|
"utf8"
|
|
);
|
|
}
|
|
});
|
|
console.log(appimgs)
|
|
|
|
const commonfilestrt = {};
|
|
|
|
// force some image to be in dist that are not existing in html mainly used by wco app
|
|
confwww.commonfiles.forEach(i=>{
|
|
const src = `${pathto}/${webapp}/src/${i}`;
|
|
const dist = `${pathto}/${webapp}/dist/${i}`;
|
|
//console.log(imgsrc,"---------------",imgdist)
|
|
if (!fs.existsSync(src)){
|
|
commonfilestrt[src]={ERROR:`this file does not exist request by wwws/itm/${webapp}.json`}
|
|
} else if (!fs.existsSync(dist)) {
|
|
fs.ensureDirSync(path.dirname(dist))
|
|
fs.copyFileSync(src,dist)
|
|
}
|
|
})
|
|
const imgtrt={}
|
|
Object.keys(appimgs).forEach(async (i) => {
|
|
const imgsrc = `${pathto}/${webapp}/src/${i}`;
|
|
const imgdist = `${pathto}/${webapp}/dist/${i.replace(
|
|
/(.*)\.(png|png|gif|bmp|jpg|jpeg)$/i,
|
|
"$1.webp"
|
|
)}`;
|
|
console.log("imgsrc:",imgsrc," imgdist:",imgdist)
|
|
if (fs.existsSync(imgsrc)) {
|
|
const srcstats = fs.statfsSync(imgsrc);
|
|
let newimg = sharp(imgsrc);
|
|
const srcmetadata = await newimg.metadata();
|
|
if (!fs.existsSync(imgdist)) {
|
|
if (
|
|
srcstats.size > 2 * 1024 * 1024 ||
|
|
srcmetadata.width > 1920 ||
|
|
srcmetadata.height > 1080
|
|
) {
|
|
newimg = newimg.resize({ width: 1920, height: 1080, fit: "inside" });
|
|
}
|
|
fs.ensureDirSync(path.dirname(imgdist))
|
|
await newimg.webp({ quality: 80 }).toFile(imgdist);
|
|
}
|
|
const diststats = fs.statfsSync(imgdist);
|
|
const distmetadata = await sharp(imgdist).metadata();
|
|
imgtrt[imgsrc] = {
|
|
dest: imgdist,
|
|
srcstats,
|
|
srcmetadata,
|
|
diststats,
|
|
distmetadata,
|
|
};
|
|
} else {
|
|
imgtrt[imgsrc] = { ERROR: `${imgsrc} this file does not exist` };
|
|
}
|
|
});
|
|
// saved new conf for updatelocaldb data
|
|
fs.outputJSONSync(`${pathto}/itm/${webapp}.json`, confwww, { spaces: 2 });
|
|
console.log(imgtrt);
|
|
return { status: 200, ref: "Wwws", msg: "success", data: { imgtrt,commonfilestrt } };
|
|
};
|
|
|
|
if (process.argv && process.argv.length == 5) {
|
|
const tribe = process.argv[2];
|
|
const webapp = process.argv[3];
|
|
const srcdist = process.argv[4];
|
|
console.log(
|
|
`Run from node.js command (tribe=${tribe} webapp=${webapp} yarn ${srcdist}:css)`
|
|
);
|
|
if (
|
|
fs.pathExistsSync(`../${tribe}`) &&
|
|
fs.pathExistsSync(`../${tribe}/objects/wwws/${webapp}`)
|
|
) {
|
|
console.log(Wwws.build(tribe, webapp, srcdist, {}));
|
|
} else {
|
|
console.log(
|
|
`Sorry your parameter are not set properly ../${tribe}/objects/wwws/${webapp} does not exist`
|
|
);
|
|
}
|
|
}
|
|
|
|
Wwws.initlocalwco = (tribwco, profils, lg) => {
|
|
const wco = {};
|
|
Object.keys(tribwco).forEach((t) => {
|
|
if (!fs.existsSync(`../${tribwco}`)) {
|
|
}
|
|
});
|
|
};
|
|
|
|
Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => {
|
|
const fileparam = `../${tribe}/objects/wwws/itm/${appname}.json`;
|
|
//console.log(path.resolve(fileparam));
|
|
if (!fs.existsSync(fileparam)) {
|
|
return { status: 404, ref: "Wwws", msg: "appdoesnotexist", data: {} };
|
|
}
|
|
const locals = fs.readJSONSync(fileparam);
|
|
if (!locals.pages[pagename]) {
|
|
return {
|
|
status: 200,
|
|
ref: "Wwws",
|
|
msg: "pagedoesnotexist",
|
|
data: { pagename },
|
|
};
|
|
}
|
|
if (locals.pages[pagename].version == version) {
|
|
return { status: 200, ref: "Wwws", msg: "nonewdatamodel", data: {} };
|
|
}
|
|
let authorize = false;
|
|
profils.forEach((p) => {
|
|
authorize = authorize || locals.pages[pagename].profils.includes(p);
|
|
});
|
|
if (!authorize) {
|
|
return {
|
|
status: 200,
|
|
ref: "Wwws",
|
|
msg: "forbidenaccess",
|
|
data: { pagename, profils },
|
|
};
|
|
}
|
|
//check version
|
|
const initname = `../${tribe}/tmp/initlocaldata/${tribe}_${appname}_${pagename}_${lg}_${locals.pages[pagename].version}.json`;
|
|
if (fs.existsSync(initname) && 1 != 1) {
|
|
const init = fs.readJsonSync(initname);
|
|
if (init.app.version == locals.app.version) {
|
|
return { status: 200, ref: "Wwws", msg: "datamodelnoupdate", data: init };
|
|
}
|
|
}
|
|
const localstorage = {
|
|
version: locals.pages[pagename].version,
|
|
headers: locals.apxtri.headers,
|
|
confpage: locals.pages[pagename].confpage,
|
|
req: {},
|
|
itm: {},
|
|
itms: {},
|
|
options: {},
|
|
tpl: {},
|
|
tpldata: {},
|
|
ref: {},
|
|
schema: [],
|
|
};
|
|
localstorage.headers.xlang = lg;
|
|
// A faire plus tard charger tous les referentiele et les data pour une page adminpage
|
|
/* if (pagename=="pageadmin"){
|
|
// load any referentialdata
|
|
glob.Sync(`../${tribe}/objects/*.json`).forEach(f=>{
|
|
if (!localstorage.schema.includes(`${tribe}/objects/${path.basename(f,".json")}`)){
|
|
localstorage.schema.push(`${tribe}/objects/${path.basename(f,".json")}`)
|
|
}
|
|
})
|
|
|
|
}
|
|
*/
|
|
const loc = locals.pages[pagename];
|
|
if (loc.itms) {
|
|
Object.keys(loc.itms).forEach((r) => {
|
|
const src = `../${loc.itms[r]}.json`;
|
|
if (fs.existsSync(src)) {
|
|
localstorage.itms[r] = fs.readJSONSync(src);
|
|
} else {
|
|
localstorage.itms[
|
|
r
|
|
] = `Check your ${fileparam} for itms in ${pagename} and ${r}`;
|
|
}
|
|
});
|
|
}
|
|
if (loc.ref) {
|
|
Object.keys(loc.ref).forEach((r) => {
|
|
const src = `../${loc.ref[r]}_${lg}.json`;
|
|
if (fs.existsSync(src)) {
|
|
localstorage.ref[r] = fs.readJSONSync(src);
|
|
} else {
|
|
localstorage.ref[
|
|
r
|
|
] = `Check your ${fileparam} for ref in ${pagename} and ${r}`;
|
|
}
|
|
});
|
|
}
|
|
if (loc.options) {
|
|
Object.keys(loc.options).forEach((r) => {
|
|
const src = `../${loc.options[r]}_${lg}.json`;
|
|
//console.log(path.resolve(src))
|
|
|
|
if (fs.existsSync(src)) {
|
|
localstorage.options[r] = fs.readJSONSync(src);
|
|
} else {
|
|
localstorage.options[
|
|
r
|
|
] = `Check your ${fileparam} for options in ${pagename} profil and ${r}`;
|
|
}
|
|
});
|
|
}
|
|
if (!loc.tpl) loc.tpl = {};
|
|
if (!loc.tpldata) loc.tpldata = {};
|
|
if (loc.components) {
|
|
loc.components.forEach((c) => {
|
|
console.log("ggggggggggggggggg", c);
|
|
const componame = path.basename(c);
|
|
loc.tpl[componame] = `${c}/${componame}.mustache`;
|
|
loc.tpldata[componame] = `${c}/${componame}`;
|
|
});
|
|
}
|
|
if (loc.tpl) {
|
|
Object.keys(loc.tpl).forEach((r) => {
|
|
let src = `../${loc.tpl[r]}`;
|
|
if (!fs.existsSync(src)) {
|
|
src += `_${lg}.mustache`;
|
|
}
|
|
//console.log(path.resolve(src))
|
|
if (fs.existsSync(src)) {
|
|
localstorage.tpl[r] = fs.readFileSync(src, "utf-8");
|
|
} else {
|
|
localstorage.tpl[
|
|
r
|
|
] = `Check your ${fileparam} for template in ${pagename} profil and ${r}`;
|
|
}
|
|
});
|
|
}
|
|
if (loc.tpldata) {
|
|
Object.keys(loc.tpldata).forEach((r) => {
|
|
let src = `../${loc.tpldata[r]}`;
|
|
//console.log(path.resolve(src))
|
|
if (!fs.existsSync(src)) {
|
|
src += `_${lg}.json`;
|
|
}
|
|
if (fs.existsSync(src)) {
|
|
localstorage.tpldata[r] = fs.readJSONSync(src);
|
|
} else {
|
|
localstorage.tpldata[
|
|
r
|
|
] = `Check your ${fileparam} for template in ${pagename} profil and ${r} in tpldata`;
|
|
}
|
|
});
|
|
}
|
|
if (loc.schema) {
|
|
loc.schema.forEach((objpath) => {
|
|
const name = path.basename(objpath);
|
|
const schema = Odmdb.Schema(`../${objpath}`, false, lg);
|
|
if (schema.status == 200) {
|
|
localstorage.schema[name] = schema.data.schema;
|
|
} else {
|
|
//console.log(schema);
|
|
let msg = `Check your ${fileparam} for schema in ${pagename}, for ${schema.status} ${schema.ref} ${schema.msg} :`;
|
|
if (schema.status == 406) {
|
|
if (schema.msg) msg += schema.msg;
|
|
if (schema.multimsg) {
|
|
schema.multimsg.forEach((err) => {
|
|
msg += `${err.msg} ${JSON.stringify(err.data)})`;
|
|
});
|
|
}
|
|
}
|
|
localstorage.schema[name] = msg;
|
|
}
|
|
});
|
|
}
|
|
if (loc.wcodata) {
|
|
//data that must be updated in case of change in the browser
|
|
localstorage.wco = loc.wcodata;
|
|
}
|
|
if (loc.appdata) {
|
|
//basic information to this page (menu, header, footer, company, other)
|
|
localstorage.appdata = loc.appdata;
|
|
}
|
|
|
|
return {
|
|
status: 200,
|
|
ref: "Wwws",
|
|
msg: "datamodelupdate",
|
|
data: localstorage,
|
|
};
|
|
};
|
|
|
|
/*Wwws.apxtriinstall = (paramconf) => {
|
|
if (fs.existsSync(`${conf.dirtown}/conf.json`)) {
|
|
console.log("You already have a conf on this town");
|
|
process.exit();
|
|
}
|
|
//first install
|
|
const nginxconf = fs.readFileSync(
|
|
`${conf.dirapi}/adminapi/www/adminapx/conf/nginx.conf.mustache`,
|
|
"utf8"
|
|
);
|
|
const proxyparams = fs.readFileSync(
|
|
"../nationchains/www/adminapx/static/tpl/nginxproxy_params.mustache",
|
|
"utf8"
|
|
);
|
|
// saved and change nginx conf
|
|
if (!fs.existsSync("/etc/nginx/nginxconf.saved")) {
|
|
fs.moveSync("/etc/nginx/nginx.conf", "/etc/nginx/nginxconf.saved");
|
|
console.log(
|
|
"your previous /etc/nginx/nginx.conf was backup in /etc/nginx/nginxconf.saved"
|
|
);
|
|
}
|
|
fs.outputFileSync(
|
|
"/etc/nginx/nginx.conf",
|
|
mustache.render(nginxconf, paramconf),
|
|
"utf8"
|
|
);
|
|
fs.outputFileSync(
|
|
"/etc/nginx/proxy_params",
|
|
mustache.render(proxyparams, paramconf),
|
|
"utf8"
|
|
);
|
|
if (!fs.existsSync(paramconf.nginx.logs)) fs.mkdirSync(paramconf.nginx.logs);
|
|
paramconf.nginx.firstinstall = true;
|
|
fs.outputJsonSync("../tribes/conf.json", paramconf, {
|
|
space: 2,
|
|
});
|
|
|
|
return Www.create(paramconf.nginx);
|
|
};
|
|
*/
|
|
Wwws.create = (paramnginx) => {
|
|
/**
|
|
* Create an nginx conf to make available a spaceweb for a tribe /www/appname/
|
|
*
|
|
*/
|
|
const res = {
|
|
status: 200,
|
|
ref: "Www",
|
|
msg: "successfulwww",
|
|
data: { website: paramnginx.website },
|
|
};
|
|
const nginxwebsite = fs.readFileSync(
|
|
`${conf.dirapi}/adminapi/www/adminapx/conf/nginxmodelwebsite.conf.mustache`,
|
|
"utf8"
|
|
);
|
|
fs.outputFileSync(
|
|
`./${paramnginx.fswww}www/nginx_${paramnginx.website}.conf`,
|
|
mustache.render(nginxwebsite, paramnginx),
|
|
"utf8"
|
|
);
|
|
if (!fs.existsSync(`./${paramnginx.fswww}www/${paramnginx.website}`)) {
|
|
//See later how to generate specific template of webapp
|
|
fs.mkdirSync(`./${paramnginx.fswww}www/${paramnginx.website}`);
|
|
}
|
|
if (!fs.existsSync(`./${paramnginx.fswww}www/cdn`)) {
|
|
//See later how to generate specific template of webapp
|
|
fs.mkdirSync(`./${paramnginx.fswww}www/cdn`);
|
|
}
|
|
//restart nginx
|
|
const { exec } = require("child_process");
|
|
exec(paramnginx.restart, (error, stdout, stderr) => {
|
|
if (error) {
|
|
if (paramnginx.firstinstall) {
|
|
console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
|
|
}
|
|
//@todo supprimer la derniere config et relancer
|
|
res.status = 500;
|
|
res.msg = "nginxError";
|
|
res.data = { msg: `${error}<br>${stdout}<br>${stderr}` };
|
|
} else {
|
|
if (paramnginx.firstinstall) {
|
|
// the tribes/conf.json is saved in apxtriinstall
|
|
console.log(
|
|
`\x1b[42m###########################################################################################\x1b[0m\n\x1b[42mWellcome into apxtri, you can now 'yarn dev' for dev or 'yarn startpm2' for prod or \n'yarn unittest' for testing purpose. Access to your town here \x1b[0m\x1b[32mhttp://adminapx\x1b[0m \x1b[42m \nto finish your town setup. Don't forget to set your localhost /etc/hosts by adding 127.0.0.1 adminapx or {LAN IP} adminapx . Check README's project to learn more. \x1b[0m\n\x1b[42m###########################################################################################\x1b[0m`
|
|
);
|
|
} else {
|
|
// add website to tribe conf
|
|
}
|
|
}
|
|
});
|
|
return res;
|
|
};
|
|
Wwws.setssl = () => {
|
|
// Run process to change nginx conf to get a ssl
|
|
};
|
|
|
|
Wwws.configlist = (tribeId) => {
|
|
//if accessright R return list of conf parameter {webapp:{conf parameter}}
|
|
const res = { status: 200, data: {} };
|
|
return res;
|
|
};
|
|
|
|
module.exports = Wwws;
|