2023-01-22 09:53:09 +00:00
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' ) ;
2023-02-10 10:48:45 +00:00
const checkdata = require ( ` ../nationchains/socialworld/contracts/checkdata.js ` ) ;
2023-01-22 09:53:09 +00:00
/ *
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 ) => {
/ * @ t r i b e i d r e q u e s t e r
@ 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
* /
2023-02-21 20:51:11 +00:00
logger . info ( 'Envoie mailjet' )
2023-01-22 09:53:09 +00:00
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 )
2023-02-21 20:51:11 +00:00
logger . info ( result . body )
2023-01-22 09:53:09 +00:00
} )
. catch ( err => {
const t = Date . now ( ) ;
MSG . result = err ;
fs . outputJson ( ` ${ config . tribes } / ${ tribeidsender } /messages/logs/error/ ${ t } .json ` , MSG )
2023-02-21 20:51:11 +00:00
logger . info ( err . statusCode , err )
2023-01-22 09:53:09 +00:00
} )
} ;
Messages . buildemail = ( tribeid , tplmessage , data ) => {
/ * @ t r i b e i d = > c l i e n t c o n c e r n e d b y s e n d i n g e m a i l g e t i n f o f r o m c l i e n t c o n f . j s o n ( c u s t o m i z a t i o n , u s e r a d m i n : { E M A I L , L O G I N } , . . . )
@ 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 } )
}
}
2023-02-21 20:51:11 +00:00
//logger.info( data )
2023-01-22 09:53:09 +00:00
// 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 : 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 ] + "###" ;
} )
2023-02-21 20:51:11 +00:00
logger . info ( contact )
2023-01-22 09:53:09 +00:00
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 => {
2023-02-21 20:51:11 +00:00
//logger.info( 'find ', f )
2023-01-22 09:53:09 +00:00
const repglob = ` ${ path . dirname ( f ) } /global.json ` ;
if ( ! dest [ repglob ] ) { dest [ repglob ] = [ ] }
dest [ repglob ] . push ( fs . readJsonSync ( f , 'utf-8' ) ) ;
fs . removeSync ( f ) ;
} )
2023-02-21 20:51:11 +00:00
//logger.info( dest )
2023-01-22 09:53:09 +00:00
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
* /
2023-02-21 20:51:11 +00:00
logger . info ( 'data' , data )
logger . info ( ` ${ config . tribes } / ${ header . xworkon } / ${ data . object } ` )
2023-01-22 09:53:09 +00:00
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 ) {
2023-02-21 20:51:11 +00:00
logger . info ( 'WARN EMAIL DESACTIVATED CHANGE TO ACTIVATE in Messages.js' )
2023-01-22 09:53:09 +00:00
//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 ) ) {
2023-02-21 20:51:11 +00:00
logger . info ( ` droit sur client ${ c } objet ${ o } : ${ ACCESSRIGHTS . data [ c ] [ o ] } ` ) ;
2023-01-22 09:53:09 +00:00
//check if intersection between user accessrigth for this object and the notification accessright is not empty @Todo replace true by intersec
2023-02-21 20:51:11 +00:00
logger . info ( 'WARN no actif filter all notif are shared with any authenticated user' )
2023-01-22 09:53:09 +00:00
const newnotif = fs . readJsonSync ( cliobjnot )
. filter ( n => { return true } ) ;
notif . notifs = notif . notifs . concat ( newnotif ) ;
}
} )
} )
return {
status : 200 ,
data : {
model : "Messages" ,
info : [ 'successgetnotification' ] ,
notif : notif
}
} ;
}
module . exports = Messages ;