Javascript helpers for JSSP, Javascript in workflows and JST in Adobe Campaign, grouped by domains such as SQL, Linux, FTP or Currency.
🐍👑🌍
SQL helpers
/**
* Performs an SQL INSERT INTO (no SQL injection protection /!\)
* @param {object} fields {column1:value1, column2:value2}
* @returns {number} The number of inserted fields
* @see sqlExec
*/
function insertInto(table, fields, log){
if(undefined === log){
log = false;
}
var columns = Object.keys(fields).join(', ');
var values = Object.keys(fields).map(function(key) {
var value = fields[key];
// if it's a string
// - remove all ' with regex /'/g
// - wrap with single-quote
if(typeof(value) == 'string'){
value = value.replace(/'/g, "");
value = "'"+value+"'";
}
// if it's null, use 'null'
else if(value == null){
value = 'null';
}
return value;
}).join(', ');
var sql = "INSERT INTO "+ table + " ("+columns+") VALUES ( "+values+" )";
if(log){
logInfo('Executing '+sql)
}
return sqlExec(sql);
}
/**
* @param {string} tableName ex: 'nms:recipient'
* @param {NLSchema} srcSchema ex: NLWS.nmsecipient
* @param {Object} params
* @param {array} params.where example: [{expr: "@a>1"}, {expr: "@b is null"}]
* @param {array} params.orderBy example: [{expr: "@id", sortDesc: "false"}]
*/
function getOneOrNull(tableName, srcSchema, params){
var query = NLWS.xtkQueryDef.create({queryDef: {
schema: tableName,
operation: "get",
select: { node: [
{expr: "@id"},
]},
where: { condition: []},
orderBy: { node: []}
}});
params.where.condition = params.where;
if(params.orderBy){
}
var res = query.ExecuteQuery();
return srcSchema.load(res.@id);
}
Linux server helpers
/**
* Helper for the ACC execCommand() function
* @param {string} command the linux command to execute
* @param {Object} params parameters [to be flexible for evolutions]
* @param {bool} params.logTheCall if true, calls logInfo(command) (default to true)
* @param {bool} params.logTheOutput if true, send the output to logInfo (default to true)
* @param {bool} params.throwOnError if true, throws an exception if linuxResultCode is != 0 (default to false)
*
* @return {Object}
* @return {int} return.linuxResultCode the linux result code (0 = success), returned by standard JSAPI execCommand function
* @return {string} return.rawOutput the linux standard output as a unique string, returned by standard JSAPI execCommand function
* @return {string[]} return.lines the linux standard output as an array of lines (lines split by \n)
*
* @example
* exec('pwd')
* exec('mkdir -p /a/b/c', {logTheCall:false})
* exec('mktemp -d', {logTheOutput:false, throwOnError: true})
*/
function exec(command, params){
if(undefined == params){
params = {};
}
var logTheCall = params.logTheCall || true;
var logTheOutput = params.logTheOutput|| true;
var throwOnError = params.throwOnError || false;
if(logTheCall){
logInfo('grl:helpers | executing | '+command);
}
var result = execCommand(command, !throwOnError); // @return [linux result code, output]
var lines = result[1].split("\n");
if(logTheOutput){
for each (var line in lines){
logInfo("" + line);
}
}
return {linuxResultCode: result[0], rawOutput: result[1], lines: lines};
}
/**
* Calls unix sed to replace a text by another text, in a file
* Usage of sed:
* - sed -i s/regular-expression/replacement-text/flags
* - -i replace in file instead of in string
*
* @param {string} replaceThis the regex to look for
* @param {string} byThis the string write instead
* @param {string} inThisFile full path of the file
* @param {Object} params for exec() params
*
* @see https://doc.ubuntu-fr.org/sed
*
* @example
* replaceInFile(',', ';', '/a/b/c/my.csv', {logTheCall:true})
*
* @todo replace | by [|] because pipe | in the sed regex must be escaped with [|]
*/
function replaceInFile(replaceThis, byThis, inThisFile, params){
var command = "sed -i 's/"+replaceThis+"/"+byThis+"/g' '"+inThisFile+"'";
return exec(command, params);
}
/**
* Remove carriage returns '\r' in file
* @param {string} fileFullpath the full path of the file
* @param {Object} params for exec() params
*/
function removeCarriageReturn(fileFullpath, params){
replaceInFile('\r', '', fileFullpath, params)
}
FTP folders
/***
* All the following functions return a string ending with /
*/
/**
* @return {string} the FTP incoming folder
*/
function getIncoming(){
return '/sftp/myinstance/incoming/';
}
function getVendor1Incoming(){
return getIncoming()+'vendor1/';
}
function getVendor1Archive(){
return getIncoming()+'vendor1/archive/';
}
function getVendor2Incoming(country){
return getIncoming()+'vendor2/'+country.toLowerCase()+'/';
}
function getVendor2Archive(country){
return getVendor2Incoming(country)+'archive/'+formatDate(new Date(), '%4Y/%2M')+'/';
}
Log helpers
function LogInfo(){
var args = Array.prototype.slice.call(arguments); // convert arguments to an array-like, @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments#Description
args.unshift('[ACME '+application.buildNumber+' LogInfo] ['+application.operator.login+']: '); // add prefix with brand name, version, type and operator login
logInfo.apply(null, args); // call standard logInfo() with apply(), @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
}
LogInfo('loading file XXX'); // [ACME 4444 LogInfo] [my_login] loading file XXX
LogInfo(); // [ACME 4444 LogInfo] [my_login]
LogInfo(null); // [ACME 4444 LogInfo] [my_login] null
function LogWarning(){
var args = Array.prototype.slice.call(arguments); // convert arguments to an array-like, @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments#Description
args.unshift('[ACME '+application.buildNumber+' LogWarning] ['+application.operator.login+']: '); // add prefix with brand name, version, type and operator login
logWarning.apply(null, args); // call standard logWarning() with apply(), @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
}
Adobe Campaign
/**
* @class DistributionOfValues
* @param schema
* @param field
*/
function DistributionOfValues(schema, field){
this.queryDef = {
operation: 'select', lineCount: 200, schema: schema,
select: {node:[
{alias: '@expr', expr: field, groupBy: 'true', noSqlBind: 'true'},
{alias: '@count', expr: 'COUNT()', label: 'Count'},
]},
orderBy: {node: [
{expr: 'COUNT()', sortDesc: 'true'},
]},
};
/**
* @return XML list
*/
this.get = function(){
this.results = NLWS.xtkQueryDef.create({queryDef:this.queryDef}).ExecuteQuery();
return this.results.getElements();
}
}
// Usage:
var d = new DistributionOfValues('nms:recipient', '[location/@countryCode]');
d.queryDef.where = {condition: [
{expr: 'DateOnly([creationInfo/@grlCreationDate]) = #2019-08-26#'},
]};
for each(var record in d.get()){
logInfo(record.$expr + record.$count);
}
/**
* @param schema string
* @param enumName string
* @example getEnum('nms:recipient', 'gender'); // The 'gender' Enumeration from the nmsRecipient schema
* @return Enumeration class or null
*/
function getEnum(schema, enumName){
var enums = application.getSchema(schema).enumerations;
for each(var enum in enums){
if(enum.name === schema + ':' + enumName){
return enum;
}
}
return null;
}
/**
* @since 20190906
* @param schema string
* @param enumName string
* @param valueValue string
* @example getEnumLabelByValue('nms:recipient', 'gender', '2'); // 'Female'
* @return label string or null
*/
function getEnumLabelByValue(schema, enumName, valueValue){
var values = getEnum(schema, enumName).values;
for each(var value in values){
if(value.value === valueValue){
return value.label;
}
}
return null;
}
Currency, money, price
/**
* Format a price to always have 2 decimals
* @example
* formatPrice('12.3') = '12.30'
*
* @param {xml|string|int|float} p the price to format
* @return {string} the formatted price
*/
function formatPrice(p){
if(typeof p == 'xml'){
p = p.toString();
}
if(typeof p == 'string'){
p = parseFloat(p);
}
return p.toFixed(2);
}
Alert Email Footer
/**
* function that returns html footer for Alert emails with system informations
* @param instance
* @param event
* @return string
*/
function getEmailFooterSystemInformation(instance, event){
var style = '<style>'+
'.table-footer-system{ border-collapse: collapse; }'+
'.table-footer-system th { background: #5B9BD5; padding: 7px 15px; color: white; }'+
'.table-footer-system td, .table-footer-system th { border-color: #2B6093; }'+
'.table-footer-system td { padding: 5px; }'+
'.error { color: red; }'+
'</style>';
var folder = NLWS.xtkFolder.load(instance.folder_id);
var campaign = (instance.operation_id > 0) ? NLWS.nmsOperation.load(instance.operation_id) : {};
var table = '<table class="table-footer-system" border="1">'+
'<thead>'+
'<tr>'+
'<th>Workflow label</th>'+
'<th>Workflow name</th>'+
'<th>Folder</th>'+
'<th>Event date</th>'+
'<th>Event id</th>'+
'<th>Task id</th>'+
'<th>Activity label (name)</th>'+
'<th>Campaign label</th>'+
'<th>Campaign name</th>'+
'<th>Last error<span class="error">*</span></th>'+
'<th>File name<span class="error">*</span></th>'+
'<th>Table name<span class="error">*</span></th>'+
'<th>Instance @ version</th>'+
'</tr>'+
'</thead>'+
'<tbody>'+
'<tr>'+
'<td>'+instance.label+'</td>'+
'<td>'+instance.internalName+'</td>'+
'<td>'+folder.fullName+'</td>'+
'<td>'+formatDate(event.processingDate, "%4Y/%2M/%2D %2H:%2N:%2S")+'</td>'+
'<td>'+event.eventIdentifier+'</td>'+
'<td>'+task.taskIdentifier+'</td>'+
'<td>'+activity.label+' ('+activity.name+')</td>'+
'<td>'+campaign.label+'</td>'+
'<td>'+campaign.internalName+'</td>'+
'<td>'+(vars.lastError || '')+'</td>'+
'<td>'+(vars.filename || '')+'</td>'+
'<td>'+(vars.tableName || '')+'</td>'+
'<td>'+application.hostName+' @ '+application.buildNumber+'</td>'+
'</tr>'+
'</tbody>'+
'<tfoot>'+
'<tr>'+
'<td colspan="99"><span class="error">*</span> indicates fields that may be empty.</td>'+
'</tr>'+
'</tfoot>'+
'</table>';
var editThisCode = '<p><span style="font-size:10px">Edit this footer in "Administration > Configuration > Javacript codes > :helpers"</span></p>';
return style+"<HR>"+
"<P>System information:</P>"+
"<P>"+table+"</P>"+editThisCode
;
}