using System;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Threading.Tasks;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Models;
using Umbraco.Forms.Core.Searchers;
namespace MyFormsExtensions
{
public class ExportToTextFiles : ExportType
{
private readonly IFormRecordSearcher _formRecordSearcher;
public ExportToTextFiles(IFormRecordSearcher formRecordSearcher)
{
_formRecordSearcher = formRecordSearcher;
Name = "Export as text files";
Description = "Export entries as text files inside a zip file";
Alias = "exportAsTextFiles";
Id = new Guid("171CABC9-2207-4575-83D5-2A77E824D5DB");
FileExtension = "zip";
Icon = "icon-zip";
}
/// <summary>
/// We do not implement this method from the interface
/// As this method is called from ExportToFile that we also override here & is expecting the file contents as a string to be written as a stream to a file
/// Which would be OK if we were creating a CSV or a single based file that can have a simple string written as a string such as one large HTML report or XML file perhaps
/// </summary>
public override Task<string> ExportRecordsAsync(Guid formId, RecordExportFilter filter) => throw new NotImplementedException();
/// <summary>
/// This gives us greater control of the export process
/// </summary>
/// <param name="formId">The form identifier.</param>
/// <param name="filter">
/// This filter contains the date range & other search parameters to limit the entries we are exporting
/// </param>
/// <param name="filepath">
/// The filepath that the export file is expecting to be served from
/// So ensure that the zip of text files is saved at this location
/// </param>
/// <returns>The final file path to serve up as the export - this is unlikely to change through the export logic</returns>
public override Task<string> ExportToFileAsync(Guid formId, RecordExportFilter filter, string filepath)
{
// Before Save - Check Path, Directory & Previous File export does not exist
string pathToSaveZipFile = filepath;
// Get the directory
var dir = Path.GetDirectoryName(filepath);
var tempFileDir = Path.Combine(dir, "text-files");
// If the path does not end with our file extension, ensure it's added
if (pathToSaveZipFile.EndsWith("." + FileExtension) == false)
{
pathToSaveZipFile += "." + FileExtension;
}
// Check that the directory where we will save the ZIP file temporarily exists
// If not just create it
if (Directory.Exists(tempFileDir) == false)
{
Directory.CreateDirectory(tempFileDir);
}
// Check if the zip file exists already - if so delete it, as we have a new update
if (File.Exists(pathToSaveZipFile))
{
File.Delete(pathToSaveZipFile);
}
// Query the DB for submissions to export based on the filter
EntrySearchResultCollection submissions = _formRecordSearcher.QueryDataBase(filter);
// Get the schema objects to a list so we can get items using position index
var schemaItems = submissions.Schema.ToList();
// We will use this to store our contents of our file to save as a text file
var fileContents = string.Empty;
// For each submission we have build up a string to save to a text file
foreach (EntrySearchResult submission in submissions.Results)
{
// The submitted data for the form submission
var submissionData = submission.Fields.ToList();
// For loop to match the schema position to the submission data
for (int i = 0; i < schemaItems.Count; i++)
{
// Concat a string of the name of the field & its stored data
fileContents += schemaItems[i].Name + ": " + submissionData[i] + Environment.NewLine;
}
// Now save the contents to a text file
// Base it on the format of the record submission unique id
var textFileName = Path.Combine(tempFileDir, submission.UniqueId + ".txt");
File.WriteAllText(textFileName, fileContents);
// Reset fileContents to be empty again
fileContents = string.Empty;
}
// Now we have a temp folder full of text files
// Generate a zip file containing them & save that
ZipFile.CreateFromDirectory(tempFileDir, pathToSaveZipFile);
// Tidy up after ourselves & delete the temp folder of text files
if (Directory.Exists(tempFileDir))
{
Directory.Delete(tempFileDir, true);
}
// Return the path where we saved the zip file containing the text files
return Task.FromResult(pathToSaveZipFile);
}
}
}