From 11887bb95fe638d81acdc9f8a361ee3e2a0df937 Mon Sep 17 00:00:00 2001 From: philc Date: Tue, 7 Jan 2025 11:05:51 +0100 Subject: [PATCH] setup update and www to manage tailwindcss --- apxtri/apxtri.js | 9 +- apxtri/models/Wwws.js | 316 ++++++++++++++++++++++++++---- apxtri/setup/setup.sh | 1 + objects/tplstrings/Tribes_en.json | 3 + package.json | 13 +- 5 files changed, 301 insertions(+), 41 deletions(-) create mode 100644 objects/tplstrings/Tribes_en.json diff --git a/apxtri/apxtri.js b/apxtri/apxtri.js index d1bd7bf..edc5c51 100755 --- a/apxtri/apxtri.js +++ b/apxtri/apxtri.js @@ -167,11 +167,10 @@ apxtri.setuptribe = async (tribe, conf) => { ); console.log("Modify /etc/nginx/nginx.conf"); fs.outputFileSync( - "/etc/nginx/nginx.conf", - Mustache.render(nginxmain, inittribe), - { asAdmin: true } + "/tmp/nginx.conf", + Mustache.render(nginxmain, inittribe) ); - } + } // "/etc/nginx/nginx.conf", // add conf for http://adminapx.adminapi const nginxapx = fs.readFileSync( "../adminapi/apxtri/setup/nginx.wwwscf", @@ -197,7 +196,7 @@ apxtri.setuptribe = async (tribe, conf) => { : fs.readJSONSync("../adminapi/apxtri/setup/initadminapi.json").nginx .restart; const { exec } = require("child_process"); - exec(nginxrestart, (error, stdout, stderr) => { + exec(`sudo mv /tmp/nginx.conf /etc/nginx/nginx.conf && ${nginxrestart}`, (error, stdout, stderr) => { if (error) { console.log("\x1b[42m", error, stdout, stderr, "x1b[0m"); process.exit(0); diff --git a/apxtri/models/Wwws.js b/apxtri/models/Wwws.js index 567788f..de21831 100644 --- a/apxtri/models/Wwws.js +++ b/apxtri/models/Wwws.js @@ -1,20 +1,261 @@ 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.initlocalwco=(tribwco,profils,lg)=>{ - const wco={} - Object.keys(tribwco).forEach(t=>{ - if (!fs.existsSync(`../${tribwco}`)){} +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`; @@ -28,7 +269,7 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { status: 200, ref: "Wwws", msg: "pagedoesnotexist", - data: { pagename } + data: { pagename }, }; } if (locals.pages[pagename].version == version) { @@ -57,19 +298,19 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { const localstorage = { version: locals.pages[pagename].version, headers: locals.apxtri.headers, - confpage:locals.pages[pagename].confpage, + confpage: locals.pages[pagename].confpage, req: {}, - itm:{}, + itm: {}, itms: {}, options: {}, tpl: {}, - tpldata:{}, + tpldata: {}, ref: {}, - schema: {}, + schema: [], }; localstorage.headers.xlang = lg; // A faire plus tard charger tous les referentiele et les data pour une page adminpage - /* if (pagename=="pageadmin"){ + /* if (pagename=="pageadmin"){ // load any referentialdata glob.Sync(`../${tribe}/objects/*.json`).forEach(f=>{ if (!localstorage.schema.includes(`${tribe}/objects/${path.basename(f,".json")}`)){ @@ -80,13 +321,15 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { } */ const loc = locals.pages[pagename]; - if (loc.itms){ + 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}`; + localstorage.itms[ + r + ] = `Check your ${fileparam} for itms in ${pagename} and ${r}`; } }); } @@ -104,10 +347,9 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { } 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 { @@ -117,14 +359,15 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { } }); } - if (!loc.tpl) loc.tpl={}; - if (!loc.tpldata) loc.tpldata={}; - if (loc.components){ - loc.components.forEach(c=>{ - const componame=path.basename(c) - loc.tpl[componame]=`${c}/${componame}.mustache` - loc.tpldata[componame]=`${c}/${componame}` - }) + 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) => { @@ -134,7 +377,7 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { } //console.log(path.resolve(src)) if (fs.existsSync(src)) { - localstorage.tpl[r] = fs.readFileSync(src,'utf-8'); + localstorage.tpl[r] = fs.readFileSync(src, "utf-8"); } else { localstorage.tpl[ r @@ -166,26 +409,33 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => { 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 + 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)})` - }) + schema.multimsg.forEach((err) => { + msg += `${err.msg} ${JSON.stringify(err.data)})`; + }); } } - localstorage.schema[ - name - ] = msg; + 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 + data: localstorage, }; }; diff --git a/apxtri/setup/setup.sh b/apxtri/setup/setup.sh index 8eae998..871dccf 100755 --- a/apxtri/setup/setup.sh +++ b/apxtri/setup/setup.sh @@ -86,6 +86,7 @@ else if [ -d "$PWD/pytri" ]; then sudo apt install python3-venv -y python3 -m venv pythonenv + . "$PWD/pythonenv/bin/activate" && pip install -r "$PWD/pytri/src/pyenvpackage.txt" && deactivate echo "Python virtual env venv installed, don't forget to use $ source ${tribe}/pythonenv/bin/activate; before running any python script then $ deactivate" fi # run as dev that will create missing file to make it works diff --git a/objects/tplstrings/Tribes_en.json b/objects/tplstrings/Tribes_en.json new file mode 100644 index 0000000..9b8f806 --- /dev/null +++ b/objects/tplstrings/Tribes_en.json @@ -0,0 +1,3 @@ +{ + "actionmissing":"L'action {{data.action}} n'existe pas pour la tribut {{data.tribe}}." +} \ No newline at end of file diff --git a/package.json b/package.json index 18b2c07..83b0da3 100755 --- a/package.json +++ b/package.json @@ -19,8 +19,8 @@ "publishtestwall": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/tribes/$space phil@wall-ants://home/phil/apxtowns/testwall-ants/tribes/$space/..", "publishwall": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/tribes/$space phil@wall-ants://home/phil/apxtowns/wall-ants/tribes/$space/..", "publishhouse": "scp -r /media/phil/usbfarm/apxtowns/dev-ants/tribes/$space phil@house-ants://home/phil/apxtowns/house-ants/tribes/$space/..", - "src:css": "tailwindcss --watch -c ../$tribe/objects/wwws/$webapp/tailwind.config.js -i ../$tribe/objects/wwws/$webapp/src/static/css/twdevstyle.css -o ../$tribe/objects/wwws/$webapp/src/static/css/twstyle.css", - "dist:css": "tailwindcss --minify -i ../$tribe/objects/wwws/$webapp/src/static/css/twdevstyle.css -o ../$tribe/objects/wwws/$webapp/dist/static/css/twstyle.css" + "src:css": "node apxtri/models/Wwws.js $tribe $webapp src && tailwindcss --watch -c ../$tribe/objects/wwws/$webapp/tailwind.config.js -i ../$tribe/objects/wwws/$webapp/src/static/css/twdevstyle.css -o ../$tribe/objects/wwws/$webapp/src/static/css/twstyle.css", + "dist:css": "node apxtri/models/Wwws.js $tribe $webapp dist && tailwindcss --minify -c ../$tribe/objects/wwws/$webapp/tailwind.config.js -i ../$tribe/objects/wwws/$webapp/src/static/css/twdevstyle.css -o ../$tribe/objects/wwws/$webapp/dist/static/css/twstyle.css" }, "commentscript": "cf wiki apxtri doc for details: yarn startpm2 -n teswallants, yarn pm2 stop testwallants, yarn pm2 delete testwallants, yarn pm2 logs --lines 200 testwall, yarn pm2 monit -n testwallants, yarn pm2 save tribe=tribeid yarn apidoc to build apidoc // space=adminapi/www/cdn/apidoc yarn publishtestwall ", "maintainers": [ @@ -65,6 +65,8 @@ "formidable": "^3.5.2", "fs-extra": "^11.2.0", "glob": "^11.0.0", + "html-minifier": "^4.0.0", + "jsdom": "^25.0.1", "jszip": "^3.10.1", "jwt-simple": "^0.5.6", "mustache": "^4.2.0", @@ -73,9 +75,14 @@ "path": "^0.12.7", "pm2": "^5.4.2", "readline-sync": "^1.4.10", - "sharp": "^0.33.4", + "sharp": "^0.33.5", "smtp-client": "^0.4.0", "stripe": "^17.3.1", "uuid": "^11.0.2" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.15", + "daisyui": "^4.12.23", + "tailwindcss": "^3.4.17" } }