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(`../../../adminapi/objects/tribes/itm/adminapi.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(`../../adminapi/objects/tribes/itm/${req.session.header.xtribe}.json`)) { const conftrib = fs.readJSONSync( `../../adminapi/objects/tribes/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=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 } }); 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":"