Skip to content

Commit

Permalink
[MNT-23479] Export CSV enabled
Browse files Browse the repository at this point in the history
  • Loading branch information
purusothaman-mm committed Jan 6, 2025
1 parent 24541a9 commit b430156
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* #%L
* Alfresco Records Management Module
* %%
* Copyright (C) 2005 - 2024 Alfresco Software Limited
* Copyright (C) 2005 - 2025 Alfresco Software Limited
* %%
* This file is part of the Alfresco software.
* -
Expand All @@ -28,9 +28,17 @@
package org.alfresco.module.org_alfresco_module_rm.script;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.alfresco.model.ContentModel;
import org.alfresco.model.RenditionModel;
Expand All @@ -39,10 +47,14 @@
import org.alfresco.repo.exporter.ACPExportPackageHandler;
import org.alfresco.repo.web.scripts.content.ContentStreamer;
import org.alfresco.repo.web.scripts.content.StreamACP;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.view.ExporterCrawlerParameters;
import org.alfresco.service.cmr.view.Location;
import org.alfresco.service.namespace.QName;
import org.alfresco.util.TempFileProvider;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
Expand All @@ -53,12 +65,15 @@
import org.springframework.extensions.webscripts.WebScriptRequest;
import org.springframework.extensions.webscripts.WebScriptResponse;

import lombok.Setter;

/**
* Creates an RM specific ACP file of nodes to export then streams it back
* to the client.
*
* @author Gavin Cornwell
*/
@Setter
public class ExportPost extends StreamACP
{
/** Logger */
Expand All @@ -69,6 +84,12 @@ public class ExportPost extends StreamACP
/** Content Streamer */
private ContentStreamer contentStreamer;

protected static final String TEMP_FILE_PREFIX = "export_";

protected static final String ZIP_EXTENSION = "zip";

protected static final String CSV_EXTENSION = "csv";

/**
* @param contentStreamer
*/
Expand All @@ -87,6 +108,8 @@ public void setContentStreamer(ContentStreamer contentStreamer)
public void execute(WebScriptRequest req, WebScriptResponse res) throws IOException
{
File tempACPFile = null;
File tempCSVFile = null;
File tempZIPFile = null;
try
{
NodeRef[] nodeRefs = null;
Expand Down Expand Up @@ -146,8 +169,22 @@ public void execute(WebScriptRequest req, WebScriptResponse res) throws IOExcept
transferFormat ? ZIP_EXTENSION : ACPExportPackageHandler.ACP_EXTENSION,
transferFormat);

// stream the ACP back to the client as an attachment (forcing save as)
contentStreamer.streamContent(req, res, tempACPFile, null, true, tempACPFile.getName(), null);
// // stream the ACP back to the client as an attachment (forcing save as)
// contentStreamer.streamContent(req, res, tempACPFile, null, true, tempACPFile.getName(), null);

// Map<String, Object> model = dynamicAuthoritiesGet.buildModel(req, res);
// create a CSV file with the same nodeRefs data
tempCSVFile = createCSV(nodeRefs);

tempZIPFile = createZipFile(tempACPFile, tempCSVFile);

// Stream the file to the browser
res.setContentType("application/zip");
res.setHeader("Content-Disposition", "attachment; filename=\"exported_files.zip\"");
res.setHeader("Content-Encoding", "UTF-8");

// stream the CSV file back to the client
contentStreamer.streamContent(req, res, tempZIPFile, null, true, tempZIPFile.getName(), null);
}
catch (IOException ioe)
{
Expand Down Expand Up @@ -182,6 +219,130 @@ public void execute(WebScriptRequest req, WebScriptResponse res) throws IOExcept

tempACPFile.delete();
}

// Try and delete the temporary CSV file
if (tempCSVFile != null) {
if (logger.isDebugEnabled()) {
logger.debug("Deleting temporary CSV file: " + tempCSVFile.getAbsolutePath());
}
tempCSVFile.delete();
}

// Try and delete the temporary ZIP file
if (tempZIPFile != null) {
if (logger.isDebugEnabled()) {
logger.debug("Deleting temporary ZIP file: " + tempZIPFile.getAbsolutePath());
}
tempZIPFile.delete();
}
}
}

private File createZipFile(File tempACPFile, File tempCSVFile) throws IOException
{
File tempZipFile = File.createTempFile("exported_files", "." + ZIP_EXTENSION);

try (FileOutputStream fos = new FileOutputStream(tempZipFile);
ZipOutputStream zipOut = new ZipOutputStream(fos)) {

// Add ACP file to the ZIP
addFileToZip(zipOut, tempACPFile, tempACPFile.getName());

// Add CSV file to the ZIP
addFileToZip(zipOut, tempCSVFile, tempCSVFile.getName());

// Finalize the ZIP archive
zipOut.close();

return tempZipFile;

} catch (IOException e) {
// Handle error while creating zip file
throw new IOException("Error creating zip file", e);
}
}

private void addFileToZip(ZipOutputStream zipOut, File file, String fileName) throws IOException
{
try (FileInputStream fis = new FileInputStream(file)) {
ZipEntry zipEntry = new ZipEntry(fileName);
zipOut.putNextEntry(zipEntry);

byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
zipOut.write(buffer, 0, length);
}

zipOut.closeEntry();
}
}

// Helper method to create a CSV file from nodeRefs or other data
public File createCSV(NodeRef[] nodeRefs) throws IOException
{
// Create temporary file in the system's temp directory
File csvFile = TempFileProvider.createTempFile(TEMP_FILE_PREFIX, "." + CSV_EXTENSION);

// Use try-with-resources to automatically close FileWriter and CSVPrinter
try (Writer writer = new FileWriter(csvFile);
CSVPrinter csvPrinter = new CSVPrinter(writer, CSVFormat.DEFAULT.builder()
.setHeader("NodeRef", "Node Name", "Description", "Parent Folder","Created On","Modified On","Created By")
.build()))
{
// Loop through each NodeRef and write data
for (NodeRef nodeRef : nodeRefs)
{
ChildAssociationRef primaryParent = nodeService.getPrimaryParent(nodeRef);
NodeRef primaryNodeRef = primaryParent.getParentRef();
String nodeName = getNodeName(nodeRef);
String description = getDescription(primaryNodeRef);
String parentFolder = getParentFolder(primaryNodeRef);
String createdOn = getCreatedOn(primaryNodeRef);
String modifiedOn = getModifiedOn(primaryNodeRef);
String createdBy = getCreatedBy(primaryNodeRef);
csvPrinter.printRecord(nodeRef.toString(), nodeName, description, parentFolder, createdOn, modifiedOn, createdBy);
}
}
return csvFile;
}

private String getNodeName(NodeRef nodeRef)
{
String nodeName = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_NAME);
return nodeName != null ? nodeName : "Unknown Node Name";
}

private String getDescription(NodeRef nodeRef)
{
// Map<QName, Serializable> properties = nodeService.getProperties(nodeRef);

String description = (String) nodeService.getProperty(nodeRef, ContentModel.PROP_DESCRIPTION);
return description != null ? description : "No Description";
}

private String getParentFolder(NodeRef nodeRef)
{
String parentFolderName = (String) nodeService.getProperty(nodeRef, ContentModel.PARENT_FOLDER);
return parentFolderName != null ? parentFolderName : "No Parent folder";
}

private String getCreatedOn(NodeRef nodeRef)
{
String createdOn = (String) nodeService.getProperty(nodeRef, ContentModel.CREATED_ON);
return createdOn != null ? createdOn : "No Creation date";
}

private String getModifiedOn(NodeRef nodeRef)
{
String modifiedOn = (String) nodeService.getProperty(nodeRef, ContentModel.MODIFIED_ON);
return modifiedOn != null ? modifiedOn : "No Modified date";
}

private String getCreatedBy(NodeRef nodeRef)
{
String createdBy = (String) nodeService.getProperty(nodeRef, ContentModel.CREATED_BY);
return createdBy != null ? createdBy : "Unknown Creater";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -466,5 +466,11 @@ public interface ContentModel
static final QName ASPECT_CASCADE_UPDATE = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "cascadeUpdate");
static final QName PROP_CASCADE_CRC = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "cascadeCRC");
static final QName PROP_CASCADE_TX = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "cascadeTx");


static final QName PARENT_FOLDER = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "parentFolder");
static final QName CREATED_ON = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "createdOn");
static final QName CREATED_BY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "createdBy");
static final QName MODIFIED_ON = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "modifiedOn");
static final QName MODIFIED_BY = QName.createQName(NamespaceService.SYSTEM_MODEL_1_0_URI, "modifiedBy");

}

0 comments on commit b430156

Please sign in to comment.