1
0
forked from apxtri/apxtri
apxtri/models/Notifications.js
2024-07-19 16:53:25 +02:00

385 lines
11 KiB
JavaScript

const glob = require("glob");
const path = require("path");
const fs = require("fs-extra");
const axios = require("axios");
const dayjs = require("dayjs");
const Mustache = require('mustache');
const Checkjson = require(`./Checkjson.js`);
//const smtp = require("smtp-client");
const nodemailer = require("nodemailer");
const conf = require(`../../../conf.json`);
const currentmod = "Notifications";
const log = conf.api.activelog.includes(currentmod);
/**
* To manage any communication between Pagan
* mayor druid emailing/sms/paper from tribe register smtp, simcard, mail api to Person(s) / Pagan(s)
* volatile notification message from tribe activities to Pagans / person ()
*
*/
const Notifications = {};
Notifications.get = (alias, tribeId) => {
const notiffile = `../../${req.params.tribeId}/notifications/${req.params.alias}.json`;
const msg = fs.existsSync(notiffile) ? fs.readJSONSync(notiffile) : {};
return {
status: 200,
ref: "Notification",
msg: "Messagelist",
data: { notif: [{ tribeId, msg }] },
};
};
/**
* Get statistic of registering email phone
*/
Notifications.statmaillist = (tribe) => {
const statinfo = {};
let csv = "email/phone;name;srckey\n";
const src = `../../${tribe}/objects/maillinglists/*.json`;
console.log(path.resolve(src));
glob.sync(src).forEach((f) => {
const name = path.basename(f, ".json");
const mlst = fs.readJSONSync(f);
Object.keys(mlst).forEach((c) => {
csv += `"${c}";"${name}";"${mlst[c].srckeys.join("-")}"\n`;
mlst[c].srckeys.forEach((s) => {
if (!statinfo[s]) statinfo[s] = {};
if (!statinfo[s][name]) statinfo[s][name] = 0;
statinfo[s][name]++;
});
});
});
// fichier csv stocker en local en attendant d'avoir un back pour stocker la reponse dans data.csv
fs.outputFileSync(`../../${tribe}/mailinglst.csv`, csv, "utf-8");
return {
status: 200,
ref: "Notifications",
msg: "statistics",
data: statinfo,
};
};
/**
* Register an typekey(email) or (phone) key into mailinglist for a tribe
*
*/
Notifications.registertolist = (key, typekey, tribe, mlist, srckey, uuid) => {
key = key.toLowerCase();
typekey = typekey == "telephone" ? "telephonefr" : typekey;
if (!Checkjson.testformat(key, typekey))
return {
status: 400,
ref: "Notifications",
msg: "formaterror",
data: { fielderr: typekey, format: typekey },
};
const destin = `../../${tribe}/objects/maillinglists/${typekey}_${mlist}.json`;
if (!fs.existsSync(destin)) {
console.log(
`######## Attention tentative d'ecriture non autorisé,le fichier n'existe pas ${destin} créer le à la main vide {}`
);
return {
status: 406,
ref: "Notifications",
msg: "destinnotallow",
data: { destin },
};
}
const filestorage = fs.existsSync(destin) ? fs.readJsonSync(destin) : {};
//if (log) console.log(currentmod,`filestorage`,filestorage, key, (filestorage[key]));
if (filestorage[key]) {
filestorage[key].dt_update = dayjs().toISOString();
if (!filestorage[key].srckeys.includes(srckey))
filestorage[key].srckeys.push(srckey);
if (!filestorage[key].uuids.includes(uuid))
filestorage[key].uuids.push(uuid);
} else {
filestorage[key] = {};
filestorage[key].dt_create = dayjs().toISOString();
filestorage[key].srckeys = [srckey];
filestorage[key].uuids = [uuid];
}
fs.outputJSONSync(destin, filestorage);
return {
status: 200,
ref: "Notifications",
msg: "registersuccess",
data: { key, typekey, tribe, mlist, srckey, uuid },
};
};
/**
* Unsubscribe an eamil or phone from a mailinglist for a tribe
*/
Notifications.unregisterfromlist = (key, typekey, tribe, mlist) => {
key = key.toLowerCase();
};
/**
* Message to send to an alias from an anonymous or not
*/
Notifications.sendcontact = (body, header) => {};
Notifications.sendsms = async (data, tribeId) => {
/**
* Never use need wallet in mailjet to test
* To set up with mailjet see https://dev.mailjet.com/sms/guides/send-sms-api/#authentication
*
* @param {string} data.To a phone number with international +3360101010101
* @param {string} data.Text text to send
*
* a conf.sms with {url:"smsurl", Token:"", From:""}
*
*
*/
if (!conf.sms) {
return {
status: 412,
ref: "Notifications",
msg: "missingconf",
data: { tribe: tribeId },
};
}
let missingk = [][("To", "Text")].forEach((k) => {
if (!data[k]) {
missingk.push(k);
}
});
if (missingk.lenght > 0) {
return {
status: 428,
ref: "Notifications",
msg: "missingdata",
data: { missingk: missingk },
};
}
let confsms = conf.sms;
if (fs.existsSync(`../../itm/${req.session.header.xtribe}.json`)) {
const conftrib = fs.readJSONSync(
`../../itm/${req.session.header.xtribe}.json`
);
if (conftrib.sms) confsms = conftrib.sms;
}
data.From = confsms.From;
const sendsms = await axios.post(confsms.url, {
headers: {
Authorization: `Bearer ${confsms.MJ_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify(data),
});
if (sendsms.status == 200) {
return {
status: 200,
ref: "Notifications",
msg: "successfullsentsms",
data: {},
};
} else {
return {
status: sendsms.status,
ref: "Notifications",
msg: "errsendsms",
data: { err: sendsms.data },
};
}
/* si tout se passe bien:
{
"From": "MJPilot",
"To": "+33600000000",
"Text": "Have a nice SMS flight with Mailjet !",
"MessageId": "2034075536371630429",
"SmsCount": 1,
"CreationTS": 1521626400,
"SentTS": 1521626402,
"Cost": {
"Value": 0.0012,
"Currency": "EUR"
},
"Status": {
"Code": 2,
"Name": "sent",
"Description": "Message sent"
}
}
}
*/
};
Notifications.manageemail = (data, template, tribe) => {
/**
* 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
*/
//console.log(data)
if (!data.emailsto || data.emailsto.length == 0) {
return {
status: 406,
ref: "Notifications",
msg: "emailstomissing",
data: data,
};
}
if (typeof data.emailsto === "string") data.emailsto = [data.emailsto];
if (!fs.existsSync(path.resolve(template))){
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 = data.Cc ? tplemail.Cc.push(data.Cc) : tplemail.Cc;
//dat.Bcc = data.Bcc ? tplemail.Bcc.push(data.Bcc) : tplemail.Bcc;
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
}
});
return sendit;
};
Notifications.sendmail = async (data, tribe) => {
/**
* * in conf global or in /itm/{tribe}.json must have valid parameter emailcontact must be authorized by the smtp
* "emailcontact": "noreply@smatchit.io",
* "smtp": {
* "host": "smtp-relay.brevo.com",
* "port": 587,
* "secure": false,
* "auth": {
* "user": "xx",
* "pass": "yy"
* }
* }
* See https://nodemailer.com/message/ for available fields to add
* @param {string} [data.from] an email authorized by smtp used priority from header xtribe
* @param {string} data.to list of email separate by ,
* @param {string} data.subject
* @param {string} data.html
* @param {string} data.text
* @param {string} [data.Cc] list of email in copy
* @param {string} [data.Bcc] list of email in hidden copy
* @param {string} [data.attachments] array of
* {filename:'filename.txt',content:'txt'},
* {filename:'img.svg',path:"https://....svg", contentType:'image/svg'}
* {filename:'img.svg',path:"https://....svg", contentType :'text/plain'}
* {filename:'img.png',path:"data:text/svg;base64.aGVsbG8gd29ybGQ="}
*
* @example data
* {"to":"wall-ants@ndda.fr",
* "subject":"Test",
* "html":"<h1>test welcome</h1>",
* "text":"test welcome",
* "attachments":[{filename:"text.txt",pathfile:"/media/phil/textA.txt","contenttype":"text/plain"}]
* }
* @return {object}
* { status: 200, ref:"pagans",msg:"",data: { } }
*
*
*/
if (!conf.smtp || !conf.emailcontact) {
return {
status: 412,
ref: "Notifications",
msg: "missingconf",
data: { tribe: tribe },
};
}
if (!data.from) {
data.from = conf.emailcontact;
}
let missingk = [];
["from", "to", "subject", "html", "text"].forEach((k) => {
if (!data[k]) {
missingk.push(k);
}
});
if (missingk.lenght > 0) {
return {
status: 428,
ref: "Notifications",
msg: "missingdata",
data: { missingk: missingk },
};
}
let confsmtp = conf.smtp;
const conftribfile = `../../itm/${tribe}.json`;
if (fs.existsSync(conftribfile)) {
const conftrib = fs.readJSONSync(conftribfile);
if (!conftrib.emailcontact){
return {
status: 428,
ref: "Notifications",
msg: "missingemailcontactinconf",
data: { tribe },
};
}
confsmtp = conftrib.smtp;
if (!data.from || data.from == conf.emailcontact) data.from = conftrib.emailcontact;
}
const transporter = await nodemailer.createTransport(confsmtp);
if (data.filelist) {
data.attachments = [];
let missingfile = [];
data.filelist.forEach((fo) => {
if (fs.existsSync(fo.pathfile)) {
} else {
missingfile.push(fo.pathfile);
}
});
if (missingfile.lenght > 0)
return {
status: 428,
ref: "Notifications",
msg: "missingfile",
data: { missingfile: missingfile },
};
}
//console.log("data:", data);
const res = await transporter.sendMail(data);
//console.log(res)
if (
res.accepted &&
data.to.split(",").reduce((acc, m) => acc && res.accepted.includes(m), true)
) {
data.accepted = res.accepted;
data.rejected = res.rejected;
return {
status: 200,
ref: "Notifications",
msg: "successfullsentemail",
data,
};
} else if (res.accepted && res.rejected) {
data.accepted = res.accepted;
data.rejected = res.rejected;
return { status: 410, ref: "Notifications", msg: "errsendmail", data };
} else {
data.errmailer = res.err;
return { status: 417, ref: "Notifications", msg: "errsendmail", data };
}
};
module.exports = Notifications;