using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Services;
using Umbraco.Forms;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Models;
using Umbraco.Forms.Core.Enums;
using Umbraco.Forms.Data.Storage;
using Umbraco.Core.Persistence;
using System.Globalization;
using Umbraco.Forms.Core.Searchers;
using Umbraco.Forms.Core.Persistence.Dtos;
using Umbraco.Forms.Core.Interfaces;
using Umbraco.Core.Scoping;
using System.Data;
using Newtonsoft.Json;
using Umbraco.Core.Models;
using NPoco;
using Umbraco.Forms.Core.Services;
using Umbraco.Web;
using Umbraco.Forms.Core.Data.Storage;
public global::NPoco.Sql BuildSqlQuery(IScope scope, RecordFilter model, string select = "")
{
throw new NotImplementedException();
}
//public EntrySearchResultCollection QueryDataBase(RecordFilter model)
//{
// throw new NotImplementedException();
//}
public EntrySearchResultCollection QueryDataBase(RecordFilter model) => this.QueryDataBaseForSubmissions(model, true);
private EntrySearchResultCollection QueryDataBaseForSubmissions(RecordFilter model, bool enforceSensitiveData = true)
{
bool? scopeFileSystems = null;
using (IScope scope = this._scopeProvider.CreateScope(IsolationLevel.Unspecified, RepositoryCacheMode.Unspecified, null, scopeFileSystems, false, false))
{
bool flag = this._umbracoContextAccessor.UmbracoContext.Security.CurrentUser.HasAccessToSensitiveData();
Form form = this._formStorage.GetForm(model.Form);
Sql sql = this.BuildSqlQuery(scope, model, "");
Page<Record> page = scope.Database.Page<Record>((long)model.StartIndex, (long)model.Length, sql);
EntrySearchResultCollection collection1 = new EntrySearchResultCollection();
collection1.TotalNumberOfResults = page.TotalItems;
collection1.TotalNumberOfPages = page.TotalPages;
EntrySearchResultCollection results = collection1;
//bool flag2 = Configuration.IsTrial && !Licensing.IsLocalBrowserRequest();
List<EntrySearchResult> list = new List<EntrySearchResult>();
if (form != null)
{
List<EntrySearchResultSchema> list2 = new List<EntrySearchResultSchema>();
foreach (Field field in form.AllFields)
{
FieldType fieldTypeByField = this._fieldTypeStorage.GetFieldTypeByField(field);
if (fieldTypeByField.StoresData)
{
EntrySearchResultSchema schema1 = new EntrySearchResultSchema();
schema1.Name = field.Caption;
schema1.Id = field.Id.ToString();
schema1.View = fieldTypeByField.RenderView;
EntrySearchResultSchema schema = schema1;
if (field.ContainsSensitiveData)
{
schema.ContainsSensitiveData = true;
}
list2.Add(schema);
}
}
EntrySearchResultSchema item = new EntrySearchResultSchema();
item.Id = "member";
item.View = "member";
item.Name = "Member";
item.ContainsSensitiveData = true;
list2.Add(item);
EntrySearchResultSchema schema4 = new EntrySearchResultSchema();
schema4.Id = "state";
schema4.View = "text";
schema4.Name = "State";
list2.Add(schema4);
EntrySearchResultSchema schema5 = new EntrySearchResultSchema();
schema5.Id = "created";
schema5.View = "date";
schema5.Name = "Created";
list2.Add(schema5);
EntrySearchResultSchema schema6 = new EntrySearchResultSchema();
schema6.Id = "updated";
schema6.View = "date";
schema6.Name = "Updated";
list2.Add(schema6);
results.schema = list2;
}
foreach (Record record in page.Items)
{
EntrySearchResult result1 = new EntrySearchResult();
result1.Id = record.Id;
result1.Form = record.Form.ToString();
result1.State = record.StateAsString;
EntrySearchResult item = result1;
int num = -model.LocalTimeOffset;
DateTimeOffset now = DateTimeOffset.Now;
TimeSpan offset = now.Offset;
int num2 = Convert.ToInt32(offset.TotalMinutes);
int num3 = num - num2;
item.Created = record.Created.AddMinutes((double)num3);
item.Updated = record.Updated.AddMinutes((double)num3);
item.UniqueId = record.UniqueId;
try
{
if (!string.IsNullOrEmpty(record.MemberKey))
{
IMember byId = this._memberService.GetById(Convert.ToInt32(record.MemberKey));
if (byId != null)
{
item.Member = byId;
}
}
}
catch (Exception ex)
{
//do nothing
}
if ((form != null) && !string.IsNullOrEmpty(record.RecordData))
{
Dictionary<string, string> dictionary = JsonConvert.DeserializeObject<Dictionary<string, string>>(record.RecordData);
List<object> list3 = new List<object>();
string str = _localizedTextService.Localize("content/isSensitiveValue", CultureInfo.CurrentCulture, null);
foreach (EntrySearchResultSchema schema2 in results.schema.Take<EntrySearchResultSchema>(results.schema.Count<EntrySearchResultSchema>() - 4))
{
if (!dictionary.ContainsKey(schema2.Id))
{
list3.Add(string.Empty);
continue;
}
//if (flag2)
//{
// list3.Add(Configuration.TrialSaveMessage);
// continue;
//}
if ((flag || !schema2.ContainsSensitiveData) ? (enforceSensitiveData && schema2.ContainsSensitiveData) : true)
{
list3.Add(str);
continue;
}
list3.Add(dictionary[schema2.Id]);
}
try
{
list3.Add(item.Member);
}
catch (Exception ex)
{
//do nothing
}
list3.Add(item.State);
list3.Add(item.Created);
list3.Add(item.Updated);
item.Fields = list3;
}
list.Add(item);
}
results.Results = list;
scope.Complete();
return results;
}
}
}
public class ExportToTextFile : ExportType
{
public ExportToTextFile()
{
this.Name = "Export as pdf files";
this.Description = "Export entries as pdf files inside a zip file";
this.Id = new Guid("171CABC9-2207-4575-83D5-2A77E824D5DB");
this.FileExtension = "zip";
this.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 string ExportRecords(RecordExportFilter filter)
{
throw new NotImplementedException();
}
/// <summary>
/// This gives us greater control of the export process
/// </summary>
/// <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 string ExportToFile(RecordExportFilter filter, string filepath)
{
// Before Save - Check Path, Directory & Previous File export does not exist
string pathToSaveZipFile = filepath;
// Check our path does not contain \\
// If not, use the filePath
if (filepath.Contains('\\') == false)
{
pathToSaveZipFile = IOHelper.MapPath(filepath);
}
// Get the directory (strip out \\ if it exists)
var dir = filepath.Substring(0, filepath.LastIndexOf('\\'));
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 (System.IO.File.Exists(pathToSaveZipFile))
{
System.IO.File.Delete(pathToSaveZipFile);
}
// Query the DB for submissions to export based on the filter
_formRecordSearcher recordSearcher = new _formRecordSearcher();
EntrySearchResultCollection submissions = recordSearcher.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 (var 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 + ".pdf");
System.IO.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 pathToSaveZipFile;
}
}
and it is giving me a weird error :
Possibly unhandled rejection: {"data":{"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object.","ExceptionType":"System.NullReferenceException","StackTrace":" at UmbracoPDFexport._formRecordSearcher.QueryDataBaseForSubmissions(RecordFilter model, Boolean enforceSensitiveData)\r\n at UmbracoPDFexport._formRecordSearcher.QueryDataBase(RecordFilter model)\r\n at UmbracoPDFexport.ExportToTextFile.ExportToFile(RecordExportFilter filter, String filepath)\r\n at Umbraco.Forms.Web.Editors.ExportController.PostGenerateExport(RecordExportFilter model)\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__3.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__6.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()"},"status":500,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"backoffice/UmbracoForms/Export/PostGenerateExport","data":{"startIndex":1,"length":20,"form":"b2413bd7-54f0-46eb-a7ad-0fde030638f1","sortBy":"created","sortOrder":"descending","states":["Approved","Submitted"],"localTimeOffset":-120,"exportType":"171cabc9-2207-4575-83d5-2a77e824d5db"},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json;charset=utf-8","X-Requested-With":"XMLHttpRequest","X-UMB-XSRF-TOKEN":"BZoVuqZZ8PZ4WL-xVe57KWIHU1cQR8u33G9G0PPFD-P4zmp6jbK9N2k1I6dC4KfJ74kYl6mPIhXCO-bnvpWy5HlWSH2Pu0CbgmbkEp4XRd9bq1XW3jN4SsMSmBVMgf2yCZCihMUAFknk-HEXWgn20Q2"}},"statusText":"","xhrStatus":"complete"}
Umbraco forms - commercial version - how to make custom export type for forms (documentation is wrong/outdated)
Greetings, I got forms commercial version couple of days ago and I have a requirement for a custom export type at forms so I followed this https://our.umbraco.com/documentation/Add-ons/UmbracoForms/Developer/Extending/Adding-a-Exporttype (the advanced example) but the FormRecordSearcher is giving me (inaccessible due to its protection level) , I also tried this here https://gist.github.com/ceee/3a4053b16f61850baa987a8888e456e6 based on a forum post from 2017 here , found here , https://our.umbraco.com/forum/umbraco-forms/86774-custom-umbraco-forms-export-to-file and it doesn't work too giving me loads of errors and missing references, can someone help me with this, I need to add pdf export type for entries as the example at documentation,
thank you.
update :
I implemented this :
using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using System.Text; using System.Threading.Tasks; using Umbraco.Core; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Services; using Umbraco.Forms; using Umbraco.Forms.Core; using Umbraco.Forms.Core.Models; using Umbraco.Forms.Core.Enums; using Umbraco.Forms.Data.Storage; using Umbraco.Core.Persistence; using System.Globalization; using Umbraco.Forms.Core.Searchers; using Umbraco.Forms.Core.Persistence.Dtos; using Umbraco.Forms.Core.Interfaces; using Umbraco.Core.Scoping; using System.Data; using Newtonsoft.Json; using Umbraco.Core.Models; using NPoco; using Umbraco.Forms.Core.Services; using Umbraco.Web; using Umbraco.Forms.Core.Data.Storage;
namespace UmbracoPDFexport { public class _formRecordSearcher : IFormRecordSearcher { private readonly IFieldTypeStorage _fieldTypeStorage; private readonly IFormStorage _formStorage; private readonly ILocalizedTextService _localizedTextService; private readonly IMemberService _memberService; private readonly IScopeProvider _scopeProvider; private readonly IUmbracoContextAccessor _umbracoContextAccessor;
and it is giving me a weird error :
does anyone have any idea what is this?
thank you.
Hi just wondering if you ever worked this out. And also what would need to be updated in the documentation.
is working on a reply...