2018-02-13 22:50:13 +00:00
'use strict' ;
const knex = require ( '../lib/knex' ) ;
const hasher = require ( 'node-object-hash' ) ( ) ;
const { enforce , filterObject } = require ( '../lib/helpers' ) ;
const dtHelpers = require ( '../lib/dt-helpers' ) ;
2018-11-18 14:38:52 +00:00
const interoperableErrors = require ( '../../shared/interoperable-errors' ) ;
2018-02-13 22:50:13 +00:00
const namespaceHelpers = require ( '../lib/namespace-helpers' ) ;
const shares = require ( './shares' ) ;
2018-09-29 11:30:29 +00:00
const files = require ( './files' ) ;
2018-09-29 18:08:49 +00:00
const dependencyHelpers = require ( '../lib/dependency-helpers' ) ;
2019-02-18 20:36:44 +00:00
const { convertFileURLs } = require ( '../lib/campaign-content' ) ;
2018-02-13 22:50:13 +00:00
2019-06-25 05:18:06 +00:00
const mailers = require ( '../lib/mailers' ) ;
const tools = require ( '../lib/tools' ) ;
const sendConfigurations = require ( './send-configurations' ) ;
const { getMergeTagsForBases } = require ( '../../shared/templates' ) ;
const { getTrustedUrl , getSandboxUrl , getPublicUrl } = require ( '../lib/urls' ) ;
const htmlToText = require ( 'html-to-text' ) ;
2018-02-13 22:50:13 +00:00
const allowedKeys = new Set ( [ 'name' , 'description' , 'type' , 'data' , 'html' , 'text' , 'namespace' ] ) ;
function hash ( entity ) {
return hasher . hash ( filterObject ( entity , allowedKeys ) ) ;
}
2018-08-02 10:19:27 +00:00
async function getByIdTx ( tx , context , id , withPermissions = true ) {
await shares . enforceEntityPermissionTx ( tx , context , 'template' , id , 'view' ) ;
const entity = await tx ( 'templates' ) . where ( 'id' , id ) . first ( ) ;
entity . data = JSON . parse ( entity . data ) ;
2018-04-02 09:58:32 +00:00
2018-08-02 10:19:27 +00:00
if ( withPermissions ) {
entity . permissions = await shares . getPermissionsTx ( tx , context , 'template' , id ) ;
}
2018-05-09 02:07:01 +00:00
2018-08-02 10:19:27 +00:00
return entity ;
}
async function getById ( context , id , withPermissions = true ) {
return await knex . transaction ( async tx => {
return await getByIdTx ( tx , context , id , withPermissions ) ;
2018-02-13 22:50:13 +00:00
} ) ;
}
2019-03-26 23:41:18 +00:00
async function _listDTAjax ( context , namespaceId , params ) {
2018-02-13 22:50:13 +00:00
return await dtHelpers . ajaxListWithPermissions (
context ,
[ { entityTypeId : 'template' , requiredOperations : [ 'view' ] } ] ,
params ,
2019-03-26 23:41:18 +00:00
builder => {
builder = builder . from ( 'templates' ) . innerJoin ( 'namespaces' , 'namespaces.id' , 'templates.namespace' ) ;
if ( namespaceId ) {
builder = builder . where ( 'namespaces.id' , namespaceId ) ;
}
return builder ;
} ,
2018-02-13 22:50:13 +00:00
[ 'templates.id' , 'templates.name' , 'templates.description' , 'templates.type' , 'templates.created' , 'namespaces.name' ]
) ;
}
2019-03-26 23:41:18 +00:00
async function listDTAjax ( context , params ) {
return await _listDTAjax ( context , undefined , params ) ;
}
async function listByNamespaceDTAjax ( context , namespaceId , params ) {
return await _listDTAjax ( context , namespaceId , params ) ;
2019-03-20 07:57:06 +00:00
}
2018-04-02 17:05:22 +00:00
async function _validateAndPreprocess ( tx , entity ) {
2018-07-31 04:34:28 +00:00
await namespaceHelpers . validateEntity ( tx , entity ) ;
// We don't check contents of the "data" because it is processed solely on the client. The client generates the HTML code we use when sending out campaigns.
2018-04-02 09:58:32 +00:00
entity . data = JSON . stringify ( entity . data ) ;
}
2018-02-13 22:50:13 +00:00
async function create ( context , entity ) {
return await knex . transaction ( async tx => {
await shares . enforceEntityPermissionTx ( tx , context , 'namespace' , entity . namespace , 'createTemplate' ) ;
2018-04-02 09:58:32 +00:00
2019-02-18 20:36:44 +00:00
if ( entity . fromSourceTemplate ) {
const template = await getByIdTx ( tx , context , entity . sourceTemplate , false ) ;
entity . type = template . type ;
entity . data = template . data ;
entity . html = template . html ;
entity . text = template . text ;
}
2018-04-02 17:05:22 +00:00
await _validateAndPreprocess ( tx , entity ) ;
2018-04-02 09:58:32 +00:00
2018-02-13 22:50:13 +00:00
const ids = await tx ( 'templates' ) . insert ( filterObject ( entity , allowedKeys ) ) ;
const id = ids [ 0 ] ;
await shares . rebuildPermissionsTx ( tx , { entityTypeId : 'template' , entityId : id } ) ;
2019-02-18 20:36:44 +00:00
if ( entity . fromSourceTemplate ) {
await files . copyAllTx ( tx , context , 'template' , 'file' , entity . sourceTemplate , 'template' , 'file' , id ) ;
convertFileURLs ( entity , 'template' , entity . sourceTemplate , 'template' , id ) ;
await tx ( 'templates' ) . update ( filterObject ( entity , allowedKeys ) ) . where ( 'id' , id ) ;
}
2018-02-13 22:50:13 +00:00
return id ;
} ) ;
}
async function updateWithConsistencyCheck ( context , entity ) {
await knex . transaction ( async tx => {
await shares . enforceEntityPermissionTx ( tx , context , 'template' , entity . id , 'edit' ) ;
const existing = await tx ( 'templates' ) . where ( 'id' , entity . id ) . first ( ) ;
if ( ! existing ) {
throw new interoperableErrors . NotFoundError ( ) ;
}
2018-04-02 09:58:32 +00:00
existing . data = JSON . parse ( existing . data ) ;
2018-02-13 22:50:13 +00:00
const existingHash = hash ( existing ) ;
if ( existingHash !== entity . originalHash ) {
throw new interoperableErrors . ChangedError ( ) ;
}
2018-04-02 17:05:22 +00:00
await _validateAndPreprocess ( tx , entity ) ;
2018-04-02 09:58:32 +00:00
2018-02-13 22:50:13 +00:00
await namespaceHelpers . validateMove ( context , entity , existing , 'template' , 'createTemplate' , 'delete' ) ;
await tx ( 'templates' ) . where ( 'id' , entity . id ) . update ( filterObject ( entity , allowedKeys ) ) ;
await shares . rebuildPermissionsTx ( tx , { entityTypeId : 'template' , entityId : entity . id } ) ;
} ) ;
}
async function remove ( context , id ) {
await knex . transaction ( async tx => {
await shares . enforceEntityPermissionTx ( tx , context , 'template' , id , 'delete' ) ;
2018-09-29 18:08:49 +00:00
await dependencyHelpers . ensureNoDependencies ( tx , context , id , [
{
entityTypeId : 'campaign' ,
query : tx => tx ( 'template_dep_campaigns' )
. where ( 'template_dep_campaigns.template' , id )
. innerJoin ( 'campaigns' , 'template_dep_campaigns.campaign' , 'campaigns.id' )
. select ( [ 'campaigns.id' , 'campaigns.name' ] )
}
] ) ;
2018-09-29 11:30:29 +00:00
await files . removeAllTx ( tx , context , 'template' , 'file' , id ) ;
2018-02-13 22:50:13 +00:00
await tx ( 'templates' ) . where ( 'id' , id ) . del ( ) ;
} ) ;
}
2019-06-25 05:18:06 +00:00
const MAX _EMAIL _COUNT = 100 ;
async function sendAsTransactionalEmail ( context , templateId , sendConfigurationId , emails , subject , mergeTags ) {
// TODO - Update this to use CampaignSender.queueMessageTx (with renderedHtml and renderedText)
if ( emails . length > MAX _EMAIL _COUNT ) {
throw new Error ( ` Cannot send more than ${ MAX _EMAIL _COUNT } emails at once ` ) ;
}
await knex . transaction ( async tx => {
const template = await getByIdTx ( tx , context , templateId , false ) ;
const sendConfiguration = await sendConfigurations . getByIdTx ( tx , context , sendConfigurationId , false , false ) ;
await shares . enforceEntityPermissionTx ( tx , context , 'sendConfiguration' , sendConfigurationId , 'sendWithoutOverrides' ) ;
const mailer = await mailers . getOrCreateMailer ( sendConfigurationId ) ;
const variablesSkeleton = {
... getMergeTagsForBases ( getTrustedUrl ( ) , getSandboxUrl ( ) , getPublicUrl ( ) ) ,
... mergeTags
} ;
for ( const email of emails ) {
const variables = {
... variablesSkeleton ,
EMAIL : email
} ;
const html = tools . formatTemplate (
template . html ,
null ,
variables ,
true
) ;
const text = ( template . text || '' ) . trim ( )
? tools . formatTemplate (
template . text ,
null ,
variables ,
false
) : htmlToText . fromString ( html , { wordwrap : 130 } ) ;
return mailer . sendTransactionalMail (
{
to : email ,
subject ,
from : {
name : sendConfiguration . from _name ,
address : sendConfiguration . from _email
} ,
html ,
text
}
) ;
}
} ) ;
}
2018-09-09 22:55:44 +00:00
module . exports . hash = hash ;
module . exports . getByIdTx = getByIdTx ;
module . exports . getById = getById ;
module . exports . listDTAjax = listDTAjax ;
2019-03-20 07:57:06 +00:00
module . exports . listByNamespaceDTAjax = listByNamespaceDTAjax ;
2018-09-09 22:55:44 +00:00
module . exports . create = create ;
module . exports . updateWithConsistencyCheck = updateWithConsistencyCheck ;
module . exports . remove = remove ;
2019-06-25 05:18:06 +00:00
module . exports . sendAsTransactionalEmail = sendAsTransactionalEmail ;