wwws webcomponent wco implementation

This commit is contained in:
philc 2025-01-23 10:24:14 +01:00
parent 11887bb95f
commit 7c92d5521e
7 changed files with 372 additions and 124 deletions

View File

@ -156,7 +156,9 @@ apxtri.setuptribe = async (tribe, conf) => {
// check nginx conf and eventually change if not starting by user "current user";
let etcnginx = fs.readFileSync("/etc/nginx/nginx.conf", "utf8");
let newnginxconf=false
if (etcnginx.split("\n")[0] !== `user ${inittribe.sudoUser};`) {
newnginxconf=true;
inittribe.mainpath = inittribe.townpath.replace(
`/${inittribe.townId}-${inittribe.nationId}`,
""
@ -196,7 +198,8 @@ apxtri.setuptribe = async (tribe, conf) => {
: fs.readJSONSync("../adminapi/apxtri/setup/initadminapi.json").nginx
.restart;
const { exec } = require("child_process");
exec(`sudo mv /tmp/nginx.conf /etc/nginx/nginx.conf && ${nginxrestart}`, (error, stdout, stderr) => {
const nginxconfmv = newnginxconf ? "sudo mv /tmp/nginx.conf /etc/nginx/nginx.conf && ":"";
exec(`${nginxconfmv}${nginxrestart}`, (error, stdout, stderr) => {
if (error) {
console.log("\x1b[42m", error, stdout, stderr, "x1b[0m");
process.exit(0);

View File

@ -3,7 +3,7 @@ const path = require("path");
const fs = require("fs-extra");
const axios = require("axios");
const dayjs = require("dayjs");
const Mustache = require('mustache');
const Mustache = require("mustache");
const Checkjson = require(`./Checkjson.js`);
//const smtp = require("smtp-client");
const nodemailer = require("nodemailer");
@ -153,7 +153,11 @@ Notifications.sendsms = async (data, tribeId) => {
};
}
let confsms = conf.sms;
if (fs.existsSync(`../adminapi/objects/tribes/itm/${req.session.header.xtribe}.json`)) {
if (
fs.existsSync(
`../adminapi/objects/tribes/itm/${req.session.header.xtribe}.json`
)
) {
const conftrib = fs.readJSONSync(
`../adminapi/objects/tribes/itm/${req.session.header.xtribe}.json`
);
@ -206,14 +210,32 @@ Notifications.sendsms = async (data, tribeId) => {
*/
};
Notifications.manageemail = (data, template, tribe) => {
Notifications.manageemail = async (data, templatename, tribe, lg,numberpersecond) => {
const sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
/**
* Manage email publipostage
* data must contain emailsto
* data optionaly can contain Cc,Bcc as array of emails and attachments as array of filename (into the server)
* Await the 1st email
* data must contain
* {
* from:"", //mandatory
* cc:[],bcc:[], present in all email sent
* emailsto:[ //mandatory
* {
* to, //mandatory
* cc,bcc,
* attachements:[{filename:"text.txt",pathfile:"/media/phil/textA.txt","contenttype":"text/plain"}],
* any properties to template
* }
* ]
* }
* emailsto contain the personnalisation data in data we can have directly cc bcc, that is added to the main
*
* template a name that exist in /tribe/{{templatename}}_{{lg}}.js
*
*/
//console.log(data)
const start = Date.now();
if (!data.emailsto || data.emailsto.length == 0) {
return {
status: 406,
@ -223,48 +245,72 @@ Notifications.manageemail = (data, template, tribe) => {
};
}
if (typeof data.emailsto === "string") data.emailsto = [data.emailsto];
if (!fs.existsSync(path.resolve(template))){
const tplpath = `../${tribe}/template/${templatename}_${lg}.js`;
if (!fs.existsSync(tplpath)) {
return {
status: 404,
ref: "Notification",
msg: "templatenotfound",
data: { template:path.resolve(template) },
}
}
const tplemail = require(path.resolve(template));
let sendit={status:200,ref:"Notifications",msg:"successfullsend"};
data.emailsto.forEach(async (e, i) => {
if (Checkjson.testformat(e, "email")) {
const dat = {};
dat.to = e;
dat.subject = Mustache.render(tplemail.subject, data);
dat.html = Mustache.render(tplemail.html, data);
dat.text = Mustache.render(tplemail.text, data);
dat.Cc=tplemail.Cc
dat.Bcc=tplemail.Bcc
/* @TODO issue with data.Cc need to test
if (data.Cc){
dat.Cc+=","+data.Cc.join(',')
}
if (data.Bcc){
dat.Bcc+=","+data.Bcc.join(',')
}
*/
if (data.attachments){
data.attachments.forEach(a=>tplemail.attachments.push(a))
}
if (i == 0) {
sendit = await Notifications.sendmail(dat, tribe);
if (sendit.status != 200) return {status:406,ref:"Notifications",msg:"emailnotsent"};
} else {
Notifications.sendmail(dat, tribe);
}
} else {
// not a well formated email @todo add a log file to follow it
data: { template: tplpath },
};
}
const results = { fail: [], success: [] };
const emailtosend = {};
// init with common propertie
Object.keys(data).forEach((k) => {
if (!["emailsto"].includes(k)) emailtosend[k] = data[k];
});
return sendit;
const tplemail = require(path.resolve(tplpath));
let sendit = { status: 200, ref: "Notifications", msg: "successfullsend" };
for (let i = 0; i < data.emailsto.length; i++) {
const email = data.emailsto[i];
emailtosend.to = email.to.toLowerCase().trim();
if (!Checkjson.testformat(emailtosend.to, "email")) {
results.fail.push({ to: emailtosend.to, err: ["errorformat"] });
} else {
emailtosend.subject = Mustache.render(tplemail.subject, email);
emailtosend.html = Mustache.render(tplemail.html, email);
emailtosend.text = Mustache.render(tplemail.text, email);
if (email.cc) {
emailtosend.cc += emailtosend.cc && emailtosend.cc != "" ? "," : "";
emailtosend.cc += email.cc.join(",");
}
if (email.bcc) {
emailtosend.bcc += emailtosend.bcc && emailtosend.bcc != "" ? "," : "";
emailtosend.bcc += email.bcc.join(",");
}
if (email.attachments) {
email.attachments.forEach((a) => tplemail.attachments.push(a));
}
//console.log(emailtosend)
sendit = await Notifications.sendmail(emailtosend, tribe);
//const sendit={status:200}
if (sendit.status == 200) {
results.success.push(emailtosend.to);
} else {
results.fail.push({ tp: emailtosend.to, status: sendit.status });
}
if ((i + 1) % numberpersecond === 0) {
console.log("Prochain lot attend 1 seconde");
await sleep(1000);
}
}
}
fs.outputJSONSync(
`../${tribe}/logs/campains/${templatename}_${lg}_${Date.now()}`,
results
);
return {
status: 200,
ref: "Wwws",
msg: "campainsent",
data: {
emailsucces: results.success.length,
emailfail: results.fail.length,
timems: Date.now() - start,
},
};
};
Notifications.sendmail = async (data, tribe) => {
@ -314,9 +360,11 @@ Notifications.sendmail = async (data, tribe) => {
data: { tribe: tribe },
};
}
if (!data.from) {
data.from = conf.emailcontact;
}
let missingk = [];
["from", "to", "subject", "html", "text"].forEach((k) => {
if (!data[k]) {
@ -335,7 +383,7 @@ Notifications.sendmail = async (data, tribe) => {
const conftribfile = `../adminapi/objects/tribes/itm/${tribe}.json`;
if (fs.existsSync(conftribfile)) {
const conftrib = fs.readJSONSync(conftribfile);
if (!conftrib.emailcontact){
if (!conftrib.emailcontact) {
return {
status: 428,
ref: "Notifications",
@ -344,9 +392,10 @@ Notifications.sendmail = async (data, tribe) => {
};
}
confsmtp = conftrib.smtp;
if (!data.from || data.from == conf.emailcontact) data.from = conftrib.emailcontact;
if (!data.from || data.from == conf.emailcontact)
data.from = conftrib.emailcontact;
}
// console.log(confsmtp)
//console.log(confsmtp);
const transporter = await nodemailer.createTransport(confsmtp);
if (data.filelist) {
data.attachments = [];
@ -368,14 +417,36 @@ Notifications.sendmail = async (data, tribe) => {
//console.log("data:", data);
let res;
let error;
try{
/*console.log(
"from:",
data.from,
" to:",
data.to,
" replyto:",
data.replyto,
" cc:",
data.cc,
" bcc:",
data.bcc,
" subject:",
data.subject
);
*/
//fs.outputFile(`../${tribe}/template/test.html`, data.html);
try {
res = await transporter.sendMail(data);
}catch(err){
console.log(err)
error=err
} catch (err) {
console.log("Erreur :", err);
if (err.code) {
error = err.code;
} else {
error = err;
}
}
if (
res && res.accepted &&
res &&
res.accepted &&
data.to.split(",").reduce((acc, m) => acc && res.accepted.includes(m), true)
) {
data.accepted = res.accepted;
@ -386,7 +457,7 @@ Notifications.sendmail = async (data, tribe) => {
msg: "successfullsentemail",
data,
};
} else if ( res && res.accepted && res.rejected) {
} else if (res && res.accepted && res.rejected) {
data.accepted = res.accepted;
data.rejected = res.rejected;
return { status: 410, ref: "Notifications", msg: "errsendmail", data };

View File

@ -11,8 +11,73 @@ const sharp = require("sharp");
const readlineSync = require("readline-sync");
const Odmdb = require("./Odmdb.js");
const conf = require(`../../../adminapi/objects/tribes/itm/adminapi.json`);
const currentmod = "Wwws";
const log = conf.api.activelog.includes(currentmod);
const Wwws = {};
Wwws.getwco = (wconame, ctx) => {
const filereq = `../${ctx.wcotribe}/objects/wco/${wconame}/${wconame}.js`;
const wcoconf = `../${ctx.wcotribe}/objects/wco/itm/${wconame}.json`;
if (!fs.existsSync(filereq) || !fs.existsSync(wcoconf)) {
return {
status: 404,
ref: "Wwws",
msg: "filedoesnotexist",
data: { js: filereq, wcoconf: wcoconf },
};
}
//check in ctx.wcotribe if ctx.tribe_ctx.code exist in
console.log("@todo don't forget to manage accessright to wco in Wwws");
//check that all tpl, tpldata, ... are available for this pagename
const webconf = `../${ctx.tribe}/objects/wwws/itm/${ctx.xapp}.json`;
const wcoinfo = fs.readJSONSync(wcoconf);
const webpage = fs.readJSONSync(webconf);
if (wcoinfo.tpl && Object.keys(wcoinfo.tpl).length > 0) {
Object.keys(wcoinfo.tpl).forEach((t) => {
if (!Object.keys(webpage.pages[ctx.pagename].tpl).includes(t)) {
webpage.pages[ctx.pagename].tpl[t] = wcoinfo.tpl[t];
}
});
}
if (wcoinfo.tpldatamodel && Object.keys(wcoinfo.tpldatamodel).length > 0) {
Object.keys(wcoinfo.tpldatamodel).forEach((t) => {
const pathtpldata = `../${ctx.tribe}/objects/wwws/${ctx.xapp}/src/tpldata/${wconame}/${t}`;
if (!Object.keys(webpage.pages[ctx.pagename].tpldata).includes(t)) {
webpage.pages[ctx.pagename].tpldata[t] = pathtpldata;
}
wcoinfo.lang.forEach((l) => {
if (!fs.existsSync(`${pathtpldata}_${l}.json`)) {
if (!fs.existsSync(`../${wcoinfo.tpldatamodel[t]}_${l}.json`)) {
fs.copySync(
`../${wcoinfo.tpldatamodel[t]}_${l}.json`,
`${pathtpldata}_${l}.json`
);
}
}
});
});
}
if (wcoinfo.ref && Object.keys(wcoinfo.ref).length > 0) {
Object.keys(wcoinfo.ref).forEach((t) => {
t=t.replace("{{tribe}}",ctx.tribe)
if (!Object.keys(webpage.pages[ctx.pagename].ref).includes(t)) {
webpage.pages[ctx.pagename].ref[t] = wcoinfo.ref[t];
}
});
}
if (wcoinfo.schema && wcoinfo.schema.length > 0)
[
wcoinfo.schema.forEach((s) => {
s = s.replace("{{tribe}}", ctx.tribe);
if (webpage.pages[ctx.pagename].schema.includes(s)) {
webpage.pages[ctx.pagename].schema.pusf(s);
}
}),
];
fs.outputJSONSync(webconf,webpage)
return { status: 200, ref:"Wwws",msg:"wcoupdatesuccessinpageconf",data: { file: path.resolve(filereq) } };
};
Wwws.build = (tribeId, webapp, srcdist, options) => {
console.log(`Building ${tribeId}/objects/wwws/${webapp}/${srcdist}`);
const pathto = `../${tribeId}/objects/wwws`;
@ -22,8 +87,9 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
} else {
confwww = {
website: webapp,
appimgs:[],
commentappimg:"Image list in src that are used by app that must be copy into /dist",
appimgs: [],
commentappimg:
"Image list in src that are used by app that must be copy into /dist",
apxtri: {
headers: {
xtrkversion: 1,
@ -60,18 +126,18 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
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` },
ref: {},
schema: [],
options: {},
wcodata: {},
appdata: {},
};
}; // test if lib exist or not if not create a symlink with node_modules
/*if (
(src.includes("static/lib/") || src.includes("wco/")) &&
!fs.existsSync(`${pathto}/${webapp}/src/${src}`)
) {
Wwws.getsymlink(`${pathto}/${webapp}/src/${src}`, tribe);
}*/
}
if (!confwww.pages[pgname].languages.includes(lg))
confwww.pages[pgname].languages.push(lg);
@ -81,7 +147,10 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
const dc = pg.window.document;
let pgscripts = [];
dc.querySelectorAll("script[src]").forEach((s) => {
if (!pgscripts.includes(s.getAttribute("src"))) {
if (
/\/api\/.*\/wwws\/objects\/wco\/itm\/.*/.test(s.src) &&
!pgscripts.includes(s.src)
) {
pgscripts.push(s.getAttribute("src"));
}
});
@ -92,9 +161,9 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
imgsrc.replace(/(.*)\.(png|png|gif|bmp|jpg|jpeg)$/, "$1.webp")
);
if (!appimgs[imgsrc]) {
appimgs[imgsrc]={pages:[]};
appimgs[imgsrc] = { pages: [] };
}
appimgs[imgsrc].pages.push(pginfo)
appimgs[imgsrc].pages.push(pginfo);
});
let wcojs = "";
pgscripts.forEach((s) => {
@ -129,7 +198,7 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
.sync(`${pathto}/${webapp}/src/tpldata/${pgname}/*.json`)
.forEach((t) => {
const tpldataname = path.parse(t).name.replace(/_..$/, "");
console.log("tpldata:",tpldataname);
console.log("tpldata:", tpldataname);
confwww.pages[pgname].tpldata[tpldataname] = `${tribeId}/${t.replace(
/_..\.json$/,
""
@ -172,30 +241,32 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
);
}
});
console.log(appimgs)
//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=>{
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`}
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)
fs.ensureDirSync(path.dirname(dist));
fs.copyFileSync(src, dist);
}
})
const imgtrt={}
});
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)
console.log("imgsrc:", imgsrc, " imgdist:", imgdist);
if (fs.existsSync(imgsrc)) {
const srcstats = fs.statfsSync(imgsrc);
let newimg = sharp(imgsrc);
@ -208,7 +279,7 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
) {
newimg = newimg.resize({ width: 1920, height: 1080, fit: "inside" });
}
fs.ensureDirSync(path.dirname(imgdist))
fs.ensureDirSync(path.dirname(imgdist));
await newimg.webp({ quality: 80 }).toFile(imgdist);
}
const diststats = fs.statfsSync(imgdist);
@ -227,7 +298,12 @@ Wwws.build = (tribeId, webapp, srcdist, options) => {
// 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 } };
return {
status: 200,
ref: "Wwws",
msg: "success",
data: { imgtrt, commonfilestrt },
};
};
if (process.argv && process.argv.length == 5) {
@ -306,7 +382,7 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => {
tpl: {},
tpldata: {},
ref: {},
schema: [],
schema: {},
};
localstorage.headers.xlang = lg;
// A faire plus tard charger tous les referentiele et les data pour une page adminpage
@ -469,7 +545,7 @@ Wwws.initlocaldata = (tribe, appname, pagename, version, profils, lg) => {
"/etc/nginx/proxy_params",
mustache.render(proxyparams, paramconf),
"utf8"
);
);ln -s ../../../../../../../adminapi/node_modules/axios axios
if (!fs.existsSync(paramconf.nginx.logs)) fs.mkdirSync(paramconf.nginx.logs);
paramconf.nginx.firstinstall = true;
fs.outputJsonSync("../tribes/conf.json", paramconf, {
@ -483,6 +559,18 @@ Wwws.create = (paramnginx) => {
/**
* Create an nginx conf to make available a spaceweb for a tribe /www/appname/
*
* create
* /dist
* /src/static/lib/
* ln -s ../../../../../../../adminapi/node_modules/axios axios
*
*
*
*
*
*
*
*
*/
const res = {
status: 200,

View File

@ -28,29 +28,42 @@ router.post(
);
/**
* @api {put} /adminapi/wwws/webcomponents - Get local web components
* @api {get} /adminapi/wwws/getwco/:wconame - Add a wco for an app
* @apiGroup Wwws
* @apiName getwco
* @apiDescription Get web component from backend to localstorage for development. This is anonymous but must be authenticated with accessright to other tribe to get their web component.<br> For production it will generate a unique id that store to add in updatelocaldb with in production space /js/uniqueid.js css/uniqueid.css pagename.html with link in it
* @apiDescription Get the wco name.js that make the wco work. It checks that the wcotribe allow the couple tribe (that request) and code exist data base from backend to localstorage for anonymous (see Get app data model)
*
* @apiBody {object} tribelistwco { wco:{tribe:[wconame]}, mode:"dev"|"prod"}
*/
router.put(
"/updatelocalwcoanonymous",
checkHeaders,
(req, res) => {
console.log("localstorage anonymous for web component", req.session.header.xalias);
req.session.header.xprofils = ["anonymous"];
console.log(req.session.header.xprofils);
//ajouter une detection de changement
const getlocal = Wwws.initlocalwco(
req.body,
req.session.header.xprofils,
req.session.header.xlang
);
res.status(getlocal.status).json(getlocal);
* @apiParam {string} name unique wco name
* @apiQuery {string} tribe that request access to
* @apiQuery {string} wcotribe where the wco is stored
* @apiQuery {string} xapp for which website is requested
* @apiQuery {string} pagename for which page name we need to add in localdb
* @apiQuery {string} code a code for tribe
*
*
* http://admin.adminapi.newdev.ants/api/adminapi/wwws/getwco/apx.js?wcotribe=adminapi&tribe=adminapi&xapp=admin&pagename=admindata&code=enjoy
*/
router.get("/getwco/:wconame", (req, res) => {
console.log(req.params);
console.log(req.query);
const mandatoryquery= ["wcotribe","tribe","xapp","pagename","code"]
let missquery=""
mandatoryquery.forEach(q=>{
if (!req.query[q] || req.query[q]=="") {
missquery+=q+" "
}
);
})
if (missquery!=""){
res.status(403).json({status:403,ref:"Wwws",msg:"missquery",data:{missquery}})
}else{
const getwco=Wwws.getwco(req.params.wconame.replace(/\.js$/,''),req.query)
if (getwco.status==200){
res.sendFile(getwco.data.file)
}else{
res.status(getwco.status).json(getwco);
}
}
});
/**
* @api {get} /adminapi/wwws/updatelocaldbanonymous/:tribe/:appname/:pagename/:version - Get localdb for app anonymous only
@ -58,11 +71,11 @@ router.put(
* @apiName getappcontextforanonymous
* @apiDescription Get data base from backend to localstorage for anonymous (see Get app data model)
*
* @apiParams {string} tribe (adminapi,smatchit,..) to looking for
* @apiParams {string} appname agregate a full data referential to store localy
* @apiParams {string} pagename app page name
* @apiParams {interger} version the current version
*/
* @apiParam {string} tribe (adminapi,smatchit,..) to looking for
* @apiParam {string} appname agregate a full data referential to store localy
* @apiParam {string} pagename app page name
* @apiParam {interger} version the current version
*/
router.get(
"/updatelocaldbanonymous/:tribe/:appname/:pagename/:version",
checkHeaders,
@ -89,10 +102,10 @@ router.get(
* @apiName getappcontext
* @apiDescription Get data base from backend to localstorage for authenticated user
*
* @apiParams {string} tribe (adminapi,smatchit,..) to looking for
* @apiParams {string} appname agregate a full data referential to store localy
* @apiParams {string} pagename app page name
* @apiParams {interger} version the current version
* @apiParam {string} tribe (adminapi,smatchit,..) to looking for
* @apiParam {string} appname agregate a full data referential to store localy
* @apiParam {string} pagename app page name
* @apiParam {interger} version the current version
* @apiSuccess {object} contain new version data model for a local web app in a PWA logical in the language of the header or if no new version exist then return
* @apiSuccessExample {json} datamodelupdate
* {"status":200, "ref":"Wwws", "msg":"datamodelupdate", "data":{version,confpage,profils,schema,options,ref,tpl,tpldata}}
@ -106,7 +119,8 @@ router.get(
*/
router.get(
"/updatelocaldb/:tribe/:appname/:pagename/:version",
checkHeaders, isAuthenticated,
checkHeaders,
isAuthenticated,
(req, res) => {
console.log("pass localstorage", req.session.header.xalias);
console.log(req.session.header.xprofils);
@ -128,8 +142,8 @@ router.get(
* @apiName createPagename
* @apiDescription Create a pagename from /appscreen/template/:pagename with
*
* @apiParams {string} tribe (adminapi,smatchit,..) to looking for
* @apiParams {string} appname agregate a full data referential to store localy
* @apiParam {string} tribe (adminapi,smatchit,..) to looking for
* @apiParam {string} appname agregate a full data referential to store localy
* @apiSuccess {object} contain cuurent version of the data model
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
@ -143,9 +157,7 @@ router.get("/buildpage/:tribe/:appname/:pagename", checkHeaders, (req, res) => {
.status(404)
.json({ status: 404, ref: "Wwws", msg: "localdbnotfound", data: {} });
}
res
.status(200)
.json({
res.status(200).json({
status: 200,
ref: "Wwws",
msg: "lastversion",

View File

@ -23,6 +23,9 @@ location ~* /trk/ {
location /adminapi/Checkjson.js {
alias {{{townpath}}}/adminapi/apxtri/models/Checkjson.js;
}
location ~ ^/(?<folder>[^/]+)/node_modules/(?<file>.+)$ {
alias {{{townpath}}}/$folder/node_modules/$file;
}
location /setup.sh {
alias {{{townpath}}}/adminapi/apxtri/setup/setup.sh;
}

71
schema/wco.json Normal file
View File

@ -0,0 +1,71 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "adminapi/schema/wco",
"title": "web components",
"description": "A web component wco is a folder with list of mustache and one name.js that deal all the business logic",
"type": "object",
"properties": {
"wconame": {
"description": "Folder name into a tribeId/objects/wco/itm",
"title": "Web component reusable in web project based with tailwindcss",
"type": "string"
},
"owner": {
"description": "owner that earn some fees",
"type": "string"
},
"codehash": {
"description": "Code signature of alias publickey",
"type": "string"
},
"thumbnail":{
"title":"Thumbnail of the component",
"type":"string"
},
"title":{
"title":"Short description of the wco",
"type":"string"
},
"description":{
"title":"Long description in html of the component",
"type":"string"
},
"tpl":{
"description":"list of mustache template to manage components each file must ended by _xx.mustache where xx is the language of the template, so you can add translation easily",
"type":"array"
},
"tpldata":{
"description":"Example of tpldata that you have to add in your local to customize the wco ended by _xx.json where xx is the language of the template",
"type":"array"
}
},
"required": [
"wconame",
"owner",
"title"
],
"apxid": "wconame",
"apxuniquekey": [
"wconame"
],
"apxidx": [
{
"name": "lst_wconame",
"type": "array",
"keyval": "wconame"
}
],
"apxaccessrights": {
"owner": {
"D": [],
"R": [],
"U": []
},
"mayor": {
"C": []
},
"person": {
"R": []
}
}
}

View File

@ -1,6 +1,6 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "nationchains/schema/www",
"$id": "adminapi/schema/wwws",
"title": "www",
"description": "A space web available for a domaine, with accessright",
"type": "object",