438 lines
16 KiB
JavaScript
Executable File
438 lines
16 KiB
JavaScript
Executable File
/* eslint-disable no-unused-vars */
|
|
|
|
const bcrypt = require('bcrypt')
|
|
const fs = require('fs-extra')
|
|
const path = require('path')
|
|
const jsonfile = require('jsonfile')
|
|
const glob = require('glob')
|
|
const Mustache = require('mustache')
|
|
const jwt = require('jwt-simple')
|
|
const { DateTime } = require('luxon')
|
|
const UUID = require('uuid')
|
|
const Outputs = require('../models/Outputs.js')
|
|
const config = require('../tribes/townconf.js')
|
|
const checkdata = require('../nationchains/socialworld/contracts/checkdata.js')
|
|
|
|
const logger = require('../core/logger')
|
|
/*
|
|
Message manager
|
|
* Manage apixtribe message at different level
|
|
* this means that an object (most often a user or a contact) want to send a question to an other user.
|
|
|
|
To know more http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTONotification
|
|
|
|
*/
|
|
const Messages = {}
|
|
Messages.init = () => {
|
|
console.group('init Message')
|
|
Messages.aggregate()
|
|
}
|
|
|
|
Messages.byEmailwithmailjet = (tribeid, msg) => {
|
|
/* @tribeid requester
|
|
@msg =[{
|
|
To:[{Email,Name}],
|
|
Cc:[{Email,Name}],
|
|
Bcc:[{Email,Name}]}],
|
|
Subject:"Subject",
|
|
TextPart:"texte content",
|
|
HTMLPart:"html content"
|
|
}]
|
|
If tribeid has a mailjet account it use it if not then it use the apixtribe @mailjetconf = {apikeypub:, apikeypriv:, From:{Email:,Name:}}
|
|
This send a bunch of messages check the mailjet account used
|
|
FYI: Basic account is 200 email /days 6000 /month
|
|
Log is stored into
|
|
tribeidsender/messages/logs/sent/timestamp.json
|
|
@todo GUI to manage statistics and notification alert limit sender email
|
|
*/
|
|
logger.info('Envoie mailjet')
|
|
const confclient = fs.readJsonSync(`${config.tribes}/${tribeid}/clientconf.json`)
|
|
let tribeidsender = tribeid
|
|
if (confclient.smtp && confclient.smtp.mailjet) {
|
|
mailjetconf = confclient.smtp.mailjet
|
|
} else {
|
|
const confapixtribe = fs.readJsonSync(`${config.tribes}/${config.mayorId}/clientconf.json`)
|
|
if (!(confapixtribe.smtp && confapixtribe.smtp.mailjet)) {
|
|
return {
|
|
status: 403,
|
|
data: {
|
|
models: 'Messages',
|
|
info: ['nosmtpmailjet'],
|
|
moreinfo: 'missing smtpmailjet parameter in apixtribe contact your admin to activate an mailjet account on this server.'
|
|
}
|
|
}
|
|
}
|
|
tribeidsender = 'apixtribe'
|
|
mailjetconf = confapixtribe.smtp.mailjet
|
|
}
|
|
// add from from setings account
|
|
const MSG = msg.map(m => {
|
|
m.From = mailjetconf.From
|
|
return m
|
|
})
|
|
const mailjet = require('node-mailjet')
|
|
.connect(mailjetconf.apikeypub, mailjetconf.apikeypriv)
|
|
const request = mailjet.post('send', { version: 'v3.1' })
|
|
.request({ Messages: MSG })
|
|
request
|
|
.then(result => {
|
|
// store into tribeidsender/messages/logs/sent/timestamp.json
|
|
const t = Date.now()
|
|
MSG.result = result.body
|
|
fs.outputJson(`${config.tribes}/${tribeidsender}/messages/logs/sent/${t}.json`, MSG)
|
|
logger.info(result.body)
|
|
})
|
|
.catch(err => {
|
|
const t = Date.now()
|
|
MSG.result = err
|
|
fs.outputJson(`${config.tribes}/${tribeidsender}/messages/logs/error/${t}.json`, MSG)
|
|
logger.info(err.statusCode, err)
|
|
})
|
|
}
|
|
Messages.buildemail = (tribeid, tplmessage, data) => {
|
|
/* @tribeid => client concerned by sending email get info from clientconf.json (customization, useradmin:{ EMAIL,LOGIN} , ...)
|
|
@tplmessage => folder where template is available (ex: apixtribe/referentials/dataManagement/template/order)
|
|
@data { destemail = email to
|
|
if destuuid => then it get user EMAIL if exiat
|
|
subject = mail subject
|
|
// any relevant information for template message
|
|
msgcontenthtml = html msg content
|
|
msgcontenttxt = text msg content
|
|
....}
|
|
@return msg
|
|
mail part ready to send by mailjet or other smtp
|
|
*/
|
|
if (!fs.existsSync(`${config.tribes}/${tribeid}/clientconf.json`)) {
|
|
return {
|
|
status: 404,
|
|
data: { model: 'Messages', info: ['tribeiddoesnotexist'], moreinfo: `${tribeid} does not exist` }
|
|
}
|
|
}
|
|
if (!fs.existsSync(`${config.tribes}/${tplmessage}`)) {
|
|
return {
|
|
status: 404,
|
|
data: { model: 'Messages', info: ['tplmessagedoesnotexist'], moreinfo: `tpl does not exist ${tplmessage}` }
|
|
}
|
|
}
|
|
const clientconf = fs.readJsonSync(`${config.tribes}/${tribeid}/clientconf.json`)
|
|
// add clientconf.customization into data for template
|
|
data.customization = clientconf.customization
|
|
// manage receiver
|
|
const msg = { To: [{ Email: clientconf.useradmin.EMAIL, Name: clientconf.useradmin.LOGIN }] }
|
|
if (data.destemail) {
|
|
msg.To.push({ Email: data.destemail })
|
|
}
|
|
if (data.destuuid && fs.exist(`${config.tribes}/${tribeid}/users/${data.destuuid}.json`)) {
|
|
const uuidconf = fs.readJsonSync(`${config.tribes}/${tribeid}/users/${data.destuuid}.json`)
|
|
if (uuidconf.EMAIL && uuidconf.EMAIL.length > 4) {
|
|
msg.To.push({ Email: uuidconf.EMAIL, Name: uuidconf.LOGIN })
|
|
}
|
|
}
|
|
// logger.info( data )
|
|
// email content
|
|
msg.Subject = `Message from ${tribeid}`
|
|
if (data.subject) msg.Subject = data.subject
|
|
msg.TextPart = Mustache.render(fs.readFileSync(`${config.tribes}/${data.tplmessage}/contenttxt.mustache`, 'utf-8'), data)
|
|
msg.HTMLPart = Mustache.render(fs.readFileSync(`${config.tribes}/${data.tplmessage}/contenthtml.mustache`, 'utf-8'), data)
|
|
return {
|
|
status: 200,
|
|
data: { model: 'Messages', info: ['msgcustomsuccessfull'], msg }
|
|
}
|
|
}
|
|
Messages.postinfo = (data) => {
|
|
/*
|
|
Data must have:
|
|
at least one of desttribeid:,destuuid:,destemail:
|
|
if an email have to be sent tplmessage:"tribeid/referentials/dataManagement/template/tplname",
|
|
at least one of contactemail:,contactphone,contactlogin,contactuuid
|
|
any other usefull keys
|
|
|
|
Data is stored into contacts object .json
|
|
*/
|
|
let contact = '';
|
|
['contactemail', 'contactphone', 'contactuuid', 'contactlogin'].forEach(c => {
|
|
if (data[c]) contact += c + '##' + data[c] + '###'
|
|
})
|
|
logger.info(contact)
|
|
if (contact === '') {
|
|
return {
|
|
status: 404,
|
|
data: { model: 'Messages', info: ['contactundefine'], moreinfo: 'no contact field found in this form' }
|
|
}
|
|
}
|
|
if (!data.desttribeid) {
|
|
return {
|
|
status: 404,
|
|
data: { model: 'Messages', info: ['tribeidundefine'], moreinfo: 'no desttribeid field found in this form' }
|
|
}
|
|
}
|
|
// save new message in contacts
|
|
let messages = {}
|
|
if (fs.existsSync(`${config.tribes}/${data.desttribeid}/contacts/${contact}.json`)) {
|
|
messages = fs.readJsonSync(`${config.tribes}/${data.desttribeid}/contacts/${contact}.json`, 'utf-8')
|
|
}
|
|
messages[Date.now()] = data
|
|
fs.outputJsonSync(`${config.tribes}/${data.desttribeid}/contacts/${contact}.json`, messages)
|
|
|
|
// if templatemessage exist then we send alert email
|
|
// data content have to be consistent with tplmessage to generate a clean email
|
|
if (data.tplmessage && data.tplmessage !== '' &&
|
|
fs.existsSync(`${config.tribes}/${data.tplmessage}`)) {
|
|
if (!(data.msgtplhtml && data.msgtpltxt)) {
|
|
data.msgcontenthtml = `<p>${data.contactname} - ${contact.replace(/###/g, ' ').replace(/##/g, ':')}</p><p>Message: ${data.contactmessage}</p>`
|
|
data.msgcontenttxt = `${data.contactname} - ${contact}/nMessage:${data.contactmessage}\n`
|
|
} else {
|
|
data.msgcontenthtml = Mustache.render(data.msgtplhtml, data)
|
|
data.msgcontenttxt = Mustache.render(data.msgtpltxt, data)
|
|
}
|
|
const msg = Messages.buildemail(data.desttribeid, data.tplmessage, data)
|
|
if (msg.status === 200) {
|
|
Messages.byEmailwithmailjet(data.desttribeid, [msg.data.msg])
|
|
}
|
|
// we get error message eventualy but email feedback sent is not in real time
|
|
return msg
|
|
} else {
|
|
return {
|
|
status: 404,
|
|
data: { info: 'missingtpl', model: 'Messages', moreinfo: `missing template ${data.tplmessage}` }
|
|
}
|
|
}
|
|
}
|
|
Messages.aggregate = () => {
|
|
// collect each json file and add them to a global.json notifat require level
|
|
const dest = {}
|
|
try {
|
|
glob.sync(`${config.tribes}/**/notif_*.json`)
|
|
.forEach(f => {
|
|
// logger.info( 'find ', f )
|
|
const repglob = `${path.dirname(f)}/global.json`
|
|
if (!dest[repglob]) {
|
|
dest[repglob] = []
|
|
}
|
|
dest[repglob].push(fs.readJsonSync(f, 'utf-8'))
|
|
fs.removeSync(f)
|
|
})
|
|
// logger.info( dest )
|
|
Object.keys(dest)
|
|
.forEach(g => {
|
|
let notif = []
|
|
if (fs.existsSync(g)) {
|
|
notif = fs.readJsonSync(g)
|
|
}
|
|
;
|
|
fs.writeJsonSync(g, notif.concat(dest[g]), 'utf-8')
|
|
})
|
|
} catch (err) {
|
|
Console.log('ATTENTION, des Messages risquent de disparaitre et ne sont pas traitées.')
|
|
}
|
|
}
|
|
Messages.object = (data, header) => {
|
|
/*
|
|
Create or replace an object no check at all here this is only
|
|
a way to add / replace object
|
|
if deeper thing have to be checheck or done then a callback:{tribeidplugin,pluginname,functionname}
|
|
data.descttribeid tribeid to send at least to admin
|
|
data.tplmessage = folder of emailtemplate
|
|
*/
|
|
logger.info('data', data)
|
|
logger.info(`${config.tribes}/${header.xworkon}/${data.object}`)
|
|
if (!fs.existsSync(`${config.tribes}/${header.xworkon}/${data.object}`)) {
|
|
return {
|
|
status: 404,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['UnknownObjectfortribeid'],
|
|
moreinfo: `This object ${data.object} does not exist for this tribeid ${header.xworkon}`
|
|
}
|
|
}
|
|
}
|
|
if (data.uuid === 0) {
|
|
data.uuid = UUID.v4()
|
|
}
|
|
if (data.callback) {
|
|
// check from plugin data and add relevant data
|
|
const Plug = require(`${config.tribes}/${data.callback.tribeid}/plugins/${data.callback.plugins}/Model.js`)
|
|
const check = Plug[data.callback.function](header.xworkon, data)
|
|
if (check.status === 200) {
|
|
data = check.data.data
|
|
} else {
|
|
return check
|
|
}
|
|
}
|
|
;
|
|
fs.outputJsonSync(`${config.tribes}/${header.xworkon}/${data.object}/${data.uuid}.json`, data)
|
|
// if templatemessage exist then we try to send alert email
|
|
if (data.tplmessage && data.tplmessage !== '' &&
|
|
fs.existsSync(`${config.tribes}/${data.tplmessage}`)) {
|
|
const msg = Messages.buildemail(data.desttribeid, data.tplmessage, data)
|
|
if (msg.status === 200) {
|
|
logger.info('WARN EMAIL DESACTIVATED CHANGE TO ACTIVATE in Messages.js')
|
|
// Messages.byEmailwithmailjet( data.desttribeid, [ msg.data.msg ] );
|
|
}
|
|
// we get error message eventualy but email feedback sent is not in real time see notification alert in case of email not sent.
|
|
}
|
|
;
|
|
// Sendback data with new information
|
|
return {
|
|
status: 200,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['Successregisterobject'],
|
|
msg: data
|
|
}
|
|
}
|
|
}
|
|
Messages.notification = (data, header) => {
|
|
// check if valid notification
|
|
if (!req.body.elapseddays) {
|
|
req.body.elapseddays = 3
|
|
}
|
|
let missingkey = '';
|
|
['uuid', 'title', 'desc', 'icon', 'elapseddays', 'classicon'].forEach(k => {
|
|
if (!data[k]) missingkey += ` ${k},`
|
|
if (k === 'classicon' && !(['text-danger', 'text-primary', 'text-success', 'text-warning', 'text-info'].includes(data[k]))) {
|
|
missingkey += ` classicon is not well set ${data[k]}`
|
|
}
|
|
})
|
|
if (missingkey !== '') {
|
|
return {
|
|
status: 422,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['InvalidNote'],
|
|
moreinfo: `invalid notification sent cause missing key ${missingkey}`
|
|
}
|
|
}
|
|
}
|
|
if (!fs.existsSync(`${config.tribes}/${header.xworkon}/${data.object}`)) {
|
|
return {
|
|
status: 404,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['UnknownObjectfortribeid'],
|
|
moreinfo: `This object ${data.object} does not exist for this tribeid ${data.tribeid}`
|
|
}
|
|
}
|
|
}
|
|
// by default store in tmp/notification this is only for sysadmin
|
|
// user adminapixtribe
|
|
let notdest = `${config.tmp}`
|
|
|
|
if (data.app) {
|
|
const destapp = `${config.tribes}/${data.app.split(':')[0]}/spacedev/${data.app.split(':')[1]}`
|
|
if (fs.existsSync(destapp)) {
|
|
notdest = destapp
|
|
}
|
|
}
|
|
if (data.plugins) {
|
|
const destplugin = `${config.tribes}/${data.plugins.split(':')[0]}/plugins/${data.plugins.split(':')[1]}`
|
|
if (fs.existsSync(destplugin)) {
|
|
notdest = destplugin
|
|
}
|
|
}
|
|
if (data.object) {
|
|
const destobject = `${config.tribes}/${data.tribeid}/${data.object}/`
|
|
if (fs.existsSync(destobject)) {
|
|
notdest = destobject
|
|
}
|
|
}
|
|
if (!data.time) {
|
|
data.time = Date.now()
|
|
}
|
|
fs.outputJsonSync(`${notdest}/Messages/notif_${data.time}.json`, data)
|
|
|
|
return {
|
|
status: 200,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['Successregisternotification'],
|
|
notif: data
|
|
}
|
|
}
|
|
}
|
|
|
|
Messages.request = (tribeid, uuid, ACCESSRIGHTS, apprequest) => {
|
|
// list notif for each app
|
|
// list notif for each tribeid / objects if Owned
|
|
// list notif for
|
|
// check uuid notification
|
|
// Collect all notification and agregate them at relevant level;
|
|
Messages.aggregate()
|
|
|
|
// for test purpose
|
|
// const notif = jsonfile.readFileSync( `${config.tribes}/ndda/spacedev/mesa/src/static/components/notification/data_notiflist_fr.json` );
|
|
let notif
|
|
if (!fs.existsSync(`${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json`)) {
|
|
// by default we send back this but this highlght an issue
|
|
notif = {
|
|
iconnotif: 'bell',
|
|
number: 1,
|
|
notifheader: 'Your last Messages',
|
|
notiffooter: 'Check all Messages',
|
|
actionnotifmanager: '',
|
|
href: '?action=notification.view',
|
|
notifs: [{
|
|
urldetail: '#',
|
|
classicon: 'text-danger',
|
|
icon: 'alert',
|
|
title: 'File does not exist',
|
|
desc: ` ${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json`,
|
|
elapse: 'il y a 13mn'
|
|
}]
|
|
}
|
|
} else {
|
|
notif = jsonfile.readFileSync(`${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json`)
|
|
// clean up example notif
|
|
notif.notifs = []
|
|
}
|
|
// check notification for plugins of tribeid of the login
|
|
glob.sync(`${config.tribes}/${tribeid}/plugins/*/Messages/global.json`)
|
|
Object.keys(ACCESSRIGHTS.app)
|
|
.forEach(a => {
|
|
// check for each app if notification about app
|
|
const appnot = `${config.tribes}/${a.split(':')[0]}/spacedev/${a.split(':')[1]}/Messages/global.json`
|
|
if (fs.existsSync(appnot)) {
|
|
notif.notifs = notif.notifs.concat(fs.readJsonSync(appnot))
|
|
}
|
|
})
|
|
Object.keys(ACCESSRIGHTS.plugin)
|
|
.forEach(p => {
|
|
// each plugin
|
|
if (ACCESSRIGHTS.plugin[p].profil === 'owner') {
|
|
const pluginnot = `${config.tribes}/${p.split(':')[0]}/plugins/${p.split(':')[1]}/Messages/global.json`
|
|
if (fs.existsSync(pluginnot)) {
|
|
notif.notifs = notif.notifs.concat(fs.readJsonSync(pluginnot))
|
|
}
|
|
}
|
|
})
|
|
Object.keys(ACCESSRIGHTS.data)
|
|
.forEach(c => {
|
|
// each tribeid
|
|
Object.keys(ACCESSRIGHTS.data[c])
|
|
.forEach(o => {
|
|
const cliobjnot = `${config.tribes}/${c}/${o}/Messages/global.json`
|
|
// check for each tribeid / Object per accessright user
|
|
if (fs.existsSync(cliobjnot)) {
|
|
logger.info(`droit sur client ${c} objet ${o} : ${ACCESSRIGHTS.data[c][o]}`)
|
|
// check if intersection between user accessrigth for this object and the notification accessright is not empty @Todo replace true by intersec
|
|
logger.info('WARN no actif filter all notif are shared with any authenticated user')
|
|
const newnotif = fs.readJsonSync(cliobjnot)
|
|
.filter(n => {
|
|
return true
|
|
})
|
|
notif.notifs = notif.notifs.concat(newnotif)
|
|
}
|
|
})
|
|
})
|
|
return {
|
|
status: 200,
|
|
data: {
|
|
model: 'Messages',
|
|
info: ['successgetnotification'],
|
|
notif
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports = Messages
|