Reports
All of the objects that you place into Cloud CMS can be operated against to produce exports that consist of consolidated or reported information. You can use this capability to generate reports in CSV (comma-separated value) format as well as merged PDFs and ZIP archives.
Exports are generated from collections of objects. These objects might be collected by hand or they might consist of results sets from a document list, search page or report record set. The Cloud CMS user interface provides methods for generating these collections and exporting them to a variety of formats.
Exported results can be downloaded, emailed or stored within Cloud CMS as a newly-created document.
An export essentially consists of the following steps:
Start the Export. When an export is started, it is given a configuration that describes what to export and how to package up the results. The export itself runs as a background job. An
exportId
is made available to identify the export in the future to determine it's availability.Wait for the Export to Finish. Status checks are made using the
exportId
from the previous step.Do something with the Export's files. Something acquires or operates against the results of the export. For example, you might fetch the resulting ZIP document using its
exportId
. Or you might email the contents to a friend as an email attachment.
Export Configuration
The export configuration tells the export process what to work on and how to package up the results.
Common Properties
name | type | required | description |
---|---|---|---|
references | array | true | an array of reference strings for objects to be exported |
package | string | false | how to package results (either "CSV", "PDF", or "ZIP" - default is "ZIP") |
includeMetadata | boolean | false | Whether to include JSON of objects in report generation |
includeAttachments | boolean | false | Whether to include attachments of objects in report generation |
includeAttachmentIds | array | false | The string IDs of any attachments to be included |
fields | array | false | The dot-delimited string identifiers for any fields to include |
The only required property is the references
array which identifies which objects should be exported. Objects are specified as references which generally follow the format:
{type}://{platformId}/{datastoreId}/{objectId}
If includeAttachmentIds
is not specified, the "default" attachment will be exported. Typically, this is what you will want. However, in some cases, you may want to export other attachment IDs or multiple attachments per document.
If fields
is not specified, all JSON fields will be included in the export.
CSV Exports
For CSV exports, no additional properties are required. The CSV export will automatically parse the property IDs for each of the objects in your export and construct columns that are the union of properties across all objects. Object properties are then placed into rows within the CSV export.
CSV exports do not support attachments. Thus, the includeAttachments
and includeAttachmentIds
properties have no effect for this package type.
PDF Exports
For PDF exports, you can elect to have Cloud CMS auto-generate your PDFs using its built-in transformer subsystem or you can specify a PDF generation template to use to customize the PDF build. You can also elect to merge generated PDFs together (for multiple objects) into a single PDF output.
name | type | required | description |
---|---|---|---|
pdfTemplateRepositoryId | string | false | ID of the repository containing the PDF template |
pdfTemplateBranchId | string | false | ID of the branch containing the PDF template |
pdfTemplateNodeId | string | false | ID of the node for the PDF template |
mergePdfs | boolean | false | Whether to merge PDF entries into a single PDF |
To specify a PDF generation template, use the pdfTemplateRepositoryId
, pdfTemplateBranchId
and pdfTemplateNodeId
properties to point to the Cloud CMS document (or node) that contains your PDF generation template.
You can specify PDF generation templates using Freemarker, Handlebars and/or Markdown. You can also use .docx files to generate PDFs using MERGE fields.
Use the mergePdfs
property to tell the exporter to merge all of the generated PDFs together into a single document. In this case, if you're using a PDF generation template, it will be run once with the full object set for all objects at the same time.
ZIP Exports
For ZIP exports, you can have the exporter convert your ZIP entry files to PDF before zipping.
name | type | required | description |
---|---|---|---|
zipUsePdfEntries | boolean | false | whether to convert ZIP entries to PDF before zipping |
By default, the entries of the ZIP file are not converted to PDF. The raw assets are zipped up, untouched.
Exporting
You can run an export like this:
// the platform
var platform = ...;
// assume we have a collection or result map of nodes
var nodes = ...;
// export a single PDF of all of the attachments
platform.runExport(nodes, {
"package": "PDF",
"mergePdfs": true,
"includeMetadata": false,
"includeAttachments": true
}, function(exportId, status) {
// we now have the exportId!
});
This kicks off the export and waits for it to complete. Once it completes, the exportId
is given to you along with the status of the export.
Now that the export has completed, you can do things with the exported files.
Download the Export files
The export files can be accessed using simple URLs.
If the exported file is a single file, you fetch it like this:
/ref/exports/{exportId}/download
Or if the export produced multiple files, you fetch them like this:
/ref/exports/{exportId}/download/0
/ref/exports/{exportId}/download/1
...
/ref/exports/{exportId}/download/9
For any of these calls, you can also specify the download to come at you with the "Content-Disposition" header flipped on. This allows the files to be saved instead of opened within the browser. Just add the following:
?a=true&filename=<filename>
Email the Export files
You email the files from a completed export like this:
// the export ID from an export that has completed
var exportId = ...;
// assume you have an email provider
var emailProvider = ...;
// email configuration
var emailConfig = {
"to": "eddie@vanhalen.com",
"from": "steve@vai.com",
//"cc": "",
"subject": "When is the new album coming out?",
"body": "Keep on rocking"
};
emailProvider.sendForExport(exportId, emailConfig, function() {
// all done!
});
Create a new Document from the Export files
You create a new document from a completed export's files like this:
// the export ID from an export that has completed
var exportId = ...;
// assume you have a branch
var branch = ...;
var exportConfig = {
"properties": {
"title": "Hello World"
},
"extraInfo": {
"parentFolder": "/folder1/folder2"
}
};
this.createForExport(exportId, exportConfig, function(response) {
// all done!
});
Examples
Here are a few code examples that work end-to-end:
Search, Export and Download a CSV
// assume we have a branch
var branch = ...;
// assume we have a platform
var platform = ...;
branch.then(function() {
// search for nodes
var nodes;
this.search("test").then(function() {
nodes = this;
});
// export the nodes
var exportId;
this.subchain(platform).runExport(nodes, {
"package": "CSV",
"includeMetadata": true
}, function(_exportId, _status) {
exportId = _exportId;
});
// download the CSV
// create node for export result
this.then(function() {
window.location.href = "/ref/exports/" + exportId + "/download?a=true&download=export.csv";
});
});
Query, Export and Email a PDF
// assume we have a branch
var branch = ...;
// assume we have a platform
var platform = ...;
// assume we have an email provider
var emailProvider = ...;
branch.then(function() {
// search for nodes
var nodes;
this.query({
"rating": {
"$gt": 3
}
}).then(function() {
nodes = this;
});
// export the nodes
var exportId;
this.subchain(platform).runExport(nodes, {
"package": "ZIP",
"includeAttachments": true
}, function(_exportId, _status) {
exportId = _exportId;
});
// create node for export result
this.then(function() {
// email configuration
var emailConfig = {
"to": "joe@customer.com",
"from": "sales@company.com",
//"cc": "",
"subject": "Your Product Information",
"body": "Here is the product information you requested"
};
this.subchain(emailProvider).sendForExport(exportId, emailConfig, function() {
// all done!
});
});
});
Find, Export and Create a ZIP
// assume we have a branch
var branch = ...;
// assume we have a platform
var platform = ...;
branch.then(function() {
// search for nodes
var nodes;
this.find({
"query": {
"size": {
"$in": ["sm", "md", "lg", "xl"]
},
"neck": {
"$in": [16, 16.5, 17, 17.5]
},
"color": "green"
},
"search": "awesome"
}).then(function() {
nodes = this;
});
// export the nodes
var exportId;
this.subchain(platform).runExport(nodes, {
"package": "ZIP",
"zipUsePdfEntries": true,
"includeAttachments": true
}, function(_exportId, _status) {
exportId = _exportId;
});
// create node for export result
this.then(function() {
var exportConfig = {
"properties": {
"title": "Any Size, Standard Neck, Green and Awesome!"
},
"extraInfo": {
"parentFolder": "/users/user1/searches"
}
};
this.createForExport(exportId, exportConfig, function(response) {
// get the created node ID
var id = response.rows[0]._doc;
console.log("Created node ID is: " + id);
});
});
});
Export an Article as a PDF document
{
"title": "Custom Article",
"type": "object",
"properties": {
"title": {
"type": "string",
"title": "Title"
},
"body": {
"type": "string",
"title": "Body"
},
"author": {
"type": "object",
"properties": {
"firstName": {
"type": "string",
"title": "First Name"
},
"lastName": {
"type": "string",
"title": "Last Name"
},
"email": {
"type": "string",
"title": "Email"
}
}
}
}
}
And let's imagine you have a content instance like this:
{
"title": "Review of Star Trek II: The Wrath of Khan",
"body": "An amazing film with a steady pace and intriguing storyline.",
"author": {
"firstName": "Opinionated",
"lastName": "Critic",
"email": "blah@blah.com"
}
}
Let's generate a PDF for this content item. We can do so by creating another node (in this case, of type n:pdf_template
. This node doesn't need to have anything on it in terms of JSON or metadata, but it should have an attachment which will hold our PDF template. Set the attachment mimetype to application/freemarker
and enter the following:
<#assign article=objects[0]>
<div class="container">
<div class="row">
<div class="col-12">
<h2>${article.title}</h2>
<p>
By ${article.author.firstName} ${article.author.lastName}
</p>
<p>
${article.body}
</p>
<h3>Summary</h3>
<table class="table table-bordered">
<tbody>
<#list article.highlights as highlight>
<tr>
<td><b>${highlight.key}</b></td>
<td>${highlight.value}</td>
</tr>
</#list>
</tbody>
</table>
<p>
To learn more about this article, please
<a href="https://www.mycompany.com" title="Our Web Site">visit our web site</a>.
</p>
</div>
</div>
</div>
We can then tie everything together like this:
// assume we have a platform
var platform = ...;
// this is our PDF template node
var pdfTemplate = ...;
// this is the node we want to convert to pdf
var node = ...;
platform.then(function() {
// export the nodes
this.runExport([node], {
"package": "PDF",
"includeAttachments": true,
"pdfTemplateRepositoryId": pdfTemplate.getRepositoryId(),
"pdfTemplateBranchId": pdfTemplate.getBranchId(),
"pdfTemplateNodeId": pdfTemplate.getId(),
"mergePdfs": true
}, function(exportId, status) {
// redirect to our generated PDF
window.location.href = "/proxy/ref/exports/" + exportId + "/download?a=true&download=export.pdf";
});
});
The PDF template is given a model which consists of root-level objects
. Each object is a node that we pass in to the PDF template processor.
Controlling the Merge Sequence
If you set mergePdfs
to true
, then all of the nodes will be passed into a single PDF generation process and a single PDF will be produced. If some of your nodes have attachments (such as Word documents or other PDF documents) that you'd like be included as part of the merge, you can do so by specifying the mergePdfsSequence
.
The mergePdfsSequence
array consists of string values which are references to nodes within Cloud CMS. Node references take the structure:
node://<platformId>/<repositoryId>/<branchId>/<nodeId>
You can also use the special marker pdf
to indicate where the merged PDF should be inserted.
Here is an example where we generate a PDF and then merge two additional PDFs into it (one in the front and one in the back):
// assume we have a platform
var platform = ...;
// this is our PDF template node
var pdfTemplate = ...;
// this is the node we want to convert to pdf
var node = ...;
// front page PDF node
var frontPagePdfNode = ...;
// back page PDF node
var backPagePdfNode = ...;
platform.then(function() {
// export the nodes
this.runExport([node], {
"package": "PDF",
"includeAttachments": true,
"pdfTemplateRepositoryId": pdfTemplate.getRepositoryId(),
"pdfTemplateBranchId": pdfTemplate.getBranchId(),
"pdfTemplateNodeId": pdfTemplate.getId(),
"mergePdfs": true,
"mergePdfsSequence": [
frontPagePdfNode.ref(),
"pdf",
backPagePdfNode.ref()
]
}, function(exportId, status) {
// redirect to our generated PDF
window.location.href = "/proxy/ref/exports/" + exportId + "/download?a=true&download=export.pdf";
});
});