feature: task-based document bulk generation

This commit is contained in:
Gary Sharp
2022-12-04 12:03:10 +11:00
parent 13e666d95a
commit 2a2731b9f3
10 changed files with 244 additions and 112 deletions
@@ -6,10 +6,13 @@ using Disco.Services.Documents;
using Disco.Services.Documents.ManagedGroups; using Disco.Services.Documents.ManagedGroups;
using Disco.Services.Expressions; using Disco.Services.Expressions;
using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using iTextSharp.text.pdf; using iTextSharp.text.pdf;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Entity;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -60,14 +63,6 @@ namespace Disco.BI.Extensions
return dt.PdfExpressionsFromCache(Database).Values.OrderBy(e => e.Ordinal).ToList(); return dt.PdfExpressionsFromCache(Database).Values.OrderBy(e => e.Ordinal).ToList();
} }
public static Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, params string[] DataObjectsIds)
{
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjectsIds);
}
public static Stream GeneratePdfBulk(this DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, params IAttachmentTarget[] DataObjects)
{
return Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjects);
}
public static Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Target, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false) public static Stream GeneratePdf(this DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Target, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
{ {
bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression); bool generateExpression = !string.IsNullOrEmpty(dt.OnGenerateExpression);
+23 -16
View File
@@ -7,6 +7,7 @@ using Disco.Services;
using Disco.Services.Documents; using Disco.Services.Documents;
using Disco.Services.Expressions; using Disco.Services.Expressions;
using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using Disco.Services.Users; using Disco.Services.Users;
using iTextSharp.text.pdf; using iTextSharp.text.pdf;
using iTextSharp.text.pdf.codec; using iTextSharp.text.pdf.codec;
@@ -120,15 +121,19 @@ namespace Disco.BI.Interop.Pdf
return bulkPdf; return bulkPdf;
} }
} }
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, params IAttachmentTarget[] DataObjects) public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, List<IAttachmentTarget> DataObjects, IScheduledTaskStatus taskStatus)
{ {
if (DataObjects.Length > 0) if (DataObjects.Count > 0)
{ {
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length); List<Stream> generatedPdfs = new List<Stream>(DataObjects.Count);
var progressPerDoc = 80d / DataObjects.Count;
var progressDoc = 10d;
using (var state = DocumentState.DefaultState()) using (var state = DocumentState.DefaultState())
{ {
taskStatus.UpdateStatus(10, "Rendering", "Starting");
foreach (var d in DataObjects) foreach (var d in DataObjects)
{ {
taskStatus.UpdateStatus(progressDoc += progressPerDoc, $"Rendering {d.AttachmentReferenceId}");
generatedPdfs.Add(dt.GeneratePdf(Database, d, CreatorUser, Timestamp, state, true)); generatedPdfs.Add(dt.GeneratePdf(Database, d, CreatorUser, Timestamp, state, true));
state.SequenceNumber++; state.SequenceNumber++;
state.FlushScopeCache(); state.FlushScopeCache();
@@ -140,6 +145,7 @@ namespace Disco.BI.Interop.Pdf
} }
else else
{ {
taskStatus.UpdateStatus(90, "Merging", "Merging documents");
Stream bulkPdf = Utilities.JoinPdfs(InsertBlankPages, generatedPdfs); Stream bulkPdf = Utilities.JoinPdfs(InsertBlankPages, generatedPdfs);
foreach (Stream singlePdf in generatedPdfs) foreach (Stream singlePdf in generatedPdfs)
singlePdf.Dispose(); singlePdf.Dispose();
@@ -149,35 +155,36 @@ namespace Disco.BI.Interop.Pdf
return null; return null;
} }
public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, params string[] DataObjectsIds) public static Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext Database, User CreatorUser, DateTime Timestamp, bool InsertBlankPages, List<string> DataObjectsIds, IScheduledTaskStatus taskStatus)
{ {
IAttachmentTarget[] DataObjects; List<IAttachmentTarget> DataObjects;
taskStatus.UpdateStatus(0, "Resolving targets", "Resolving render targets");
switch (dt.Scope) switch (dt.Scope)
{ {
case DocumentTemplate.DocumentTemplateScopes.Device: case DocumentTemplate.DocumentTemplateScopes.Device:
DataObjects = Database.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToArray(); DataObjects = Database.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).Cast<IAttachmentTarget>().ToList();
break; break;
case DocumentTemplate.DocumentTemplateScopes.Job: case DocumentTemplate.DocumentTemplateScopes.Job:
int[] intDataObjectsIds = DataObjectsIds.Select(i => int.Parse(i)).ToArray(); var intDataObjectsIds = DataObjectsIds.Select(i => int.Parse(i)).ToList();
DataObjects = Database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray(); DataObjects = Database.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).Cast<IAttachmentTarget>().ToList();
break; break;
case DocumentTemplate.DocumentTemplateScopes.User: case DocumentTemplate.DocumentTemplateScopes.User:
DataObjects = new IAttachmentTarget[DataObjectsIds.Length]; DataObjects = new List<IAttachmentTarget>(DataObjectsIds.Count);
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++) foreach (var userId in DataObjectsIds)
{ {
string dataObjectId = DataObjectsIds[idIndex]; var user = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(userId), Database, true);
if (user == null)
DataObjects[idIndex] = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(dataObjectId), Database, true); throw new Exception($"Unknown Username specified: {userId}");
if (DataObjects[idIndex] == null) DataObjects.Add(user);
throw new Exception($"Unknown Username specified: {dataObjectId}");
} }
break; break;
default: default:
throw new InvalidOperationException("Invalid DocumentType Scope"); throw new InvalidOperationException("Invalid DocumentType Scope");
} }
return GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjects); return GenerateBulkFromTemplate(dt, Database, CreatorUser, Timestamp, InsertBlankPages, DataObjects, taskStatus);
} }
public static Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Data, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false) public static Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext Database, IAttachmentTarget Data, User CreatorUser, DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
@@ -8,6 +8,8 @@ namespace Disco.Models.UI.Config.DocumentTemplate
int StoredInstanceCount { get; set; } int StoredInstanceCount { get; set; }
List<bool> TemplatePagesHaveAttachmentId { get; set; } List<bool> TemplatePagesHaveAttachmentId { get; set; }
int TemplatePageCount { get; } int TemplatePageCount { get; }
string BulkGenerateDownloadId { get; }
string BulkGenerateDownloadFilename { get; }
List<Repository.JobType> JobTypes { get; set; } List<Repository.JobType> JobTypes { get; set; }
+1
View File
@@ -289,6 +289,7 @@
<Compile Include="Documents\AttachmentImport\ImportDirectoryMonitor.cs" /> <Compile Include="Documents\AttachmentImport\ImportDirectoryMonitor.cs" />
<Compile Include="Documents\AttachmentImport\ImportPage.cs" /> <Compile Include="Documents\AttachmentImport\ImportPage.cs" />
<Compile Include="Documents\AttachmentImport\ThumbnailUpdateTask.cs" /> <Compile Include="Documents\AttachmentImport\ThumbnailUpdateTask.cs" />
<Compile Include="Documents\DocumentBulkGenerateTask.cs" />
<Compile Include="Documents\DocumentsLog.cs" /> <Compile Include="Documents\DocumentsLog.cs" />
<Compile Include="Documents\DocumentTemplatePackageExtensions.cs" /> <Compile Include="Documents\DocumentTemplatePackageExtensions.cs" />
<Compile Include="Documents\DocumentTemplateExtensions.cs" /> <Compile Include="Documents\DocumentTemplateExtensions.cs" />
@@ -0,0 +1,96 @@
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Services.Tasks;
using Quartz;
using System;
using System.Collections.Generic;
using System.IO;
namespace Disco.Services.Documents
{
public class DocumentBulkGenerateTask : ScheduledTask
{
private const string JobDataMapContext = "Context";
public override string TaskName { get; } = "Document Template - Bulk Generate";
public override bool SingleInstanceTask { get; } = false;
public override bool CancelInitiallySupported { get; } = false;
public override void InitalizeScheduledTask(DiscoDataContext Database)
{
// clear cache
var cachePath = GetCachePath(Database);
if (Directory.Exists(cachePath))
Directory.Delete(cachePath, true);
}
public static Stream GetCached(DiscoDataContext database, string id)
{
var cachePath = GetCachePath(database);
var path = Path.Combine(cachePath, $"{id}.pdf");
if (File.Exists(path))
return File.OpenRead(path);
else
throw new FileNotFoundException();
}
public static ScheduledTaskStatus ScheduleNow(Func<DocumentTemplate, DiscoDataContext, User, DateTime, bool, List<string>, IScheduledTaskStatus, Stream> generateDelegate, DocumentTemplate documentTemplate, User creatorUser, DateTime timestamp, bool insertBlankPages, List<string> dataObjectsIds)
{
var context = new DocumentBulkGenerateContext()
{
GenerateDelegate = generateDelegate,
DocumentTemplate = documentTemplate,
CreatorUser = creatorUser,
Timestamp = timestamp,
InsertBlankPages = insertBlankPages,
DataObjectsIds = dataObjectsIds,
};
// Build Data Map
var task = new DocumentBulkGenerateTask();
JobDataMap taskData = new JobDataMap() { { JobDataMapContext, context } };
// Schedule Task
var status = task.ScheduleTask(taskData);
context.Id = status.SessionId;
return status;
}
protected override void ExecuteTask()
{
var context = (DocumentBulkGenerateContext)ExecutionContext.JobDetail.JobDataMap[JobDataMapContext];
using (var database = new DiscoDataContext())
{
var cachePath = GetCachePath(database);
if (!Directory.Exists(cachePath))
Directory.CreateDirectory(cachePath);
var filePath = Path.Combine(cachePath, $"{Status.SessionId}.pdf");
var stream = context.GenerateDelegate(context.DocumentTemplate, database, context.CreatorUser, context.Timestamp, context.InsertBlankPages, context.DataObjectsIds, Status);
using (var cacheStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None))
stream.CopyTo(cacheStream);
}
Status.UpdateStatus(100);
Status.Finished("Generated Document");
}
private static string GetCachePath(DiscoDataContext database)
=> Path.Combine(database.DiscoConfiguration.DataStoreLocation, @"DocumentTemplates\BulkGenerateCache");
private class DocumentBulkGenerateContext
{
public Func<DocumentTemplate, DiscoDataContext, User, DateTime, bool, List<string>, IScheduledTaskStatus, Stream> GenerateDelegate { get; set; }
public string Id { get; set; }
public DocumentTemplate DocumentTemplate { get; set; }
public User CreatorUser { get; set; }
public DateTime Timestamp { get; set; }
public bool InsertBlankPages { get; set; }
public List<string> DataObjectsIds { get; set; }
}
}
}
Binary file not shown.
@@ -685,19 +685,32 @@ namespace Disco.Web.Areas.API.Controllers
throw new InvalidOperationException("Unknown DocumentType Scope"); throw new InvalidOperationException("Unknown DocumentType Scope");
} }
var dataIds = DataIds.Split(new string[] { Environment.NewLine, ",", ";" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).Where(d => !string.IsNullOrEmpty(d)).ToArray(); var dataIds = DataIds.Split(new string[] { Environment.NewLine, ",", ";" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).Where(d => !string.IsNullOrEmpty(d)).ToList();
var timeStamp = DateTime.Now; var timeStamp = DateTime.Now;
var pdf = documentTemplate.GeneratePdfBulk(Database, UserService.CurrentUser, timeStamp, InsertBlankPage, dataIds);
return File(pdf, "application/pdf", string.Format("{0}_Bulk_{1:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, timeStamp)); var taskStatus = DocumentBulkGenerateTask.ScheduleNow(BI.Interop.Pdf.PdfGenerator.GenerateBulkFromTemplate, documentTemplate, UserService.CurrentUser, timeStamp, InsertBlankPage, dataIds);
var fileName = $"{documentTemplate.Id}_Bulk_{timeStamp:yyyyMMdd-HHmmss}.pdf";
taskStatus.SetFinishedUrl(Url.Action(MVC.Config.DocumentTemplate.Index(documentTemplate.Id, taskStatus.SessionId, fileName)));
if (!taskStatus.WaitUntilFinished(TimeSpan.FromSeconds(1)))
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
var stream = DocumentBulkGenerateTask.GetCached(Database, taskStatus.SessionId);
return File(stream, "application/pdf", fileName);
} }
public virtual ActionResult Generate(string id, string TargetId) public virtual ActionResult Generate(string id, string TargetId)
[DiscoAuthorize(Claims.Config.DocumentTemplate.BulkGenerate)]
public virtual ActionResult BulkGenerateDownload(string id, string fileName)
{ {
if (string.IsNullOrWhiteSpace(id)) if (string.IsNullOrWhiteSpace(id))
throw new ArgumentNullException(nameof(id)); throw new ArgumentNullException(nameof(id));
if (string.IsNullOrWhiteSpace(TargetId)) if (string.IsNullOrWhiteSpace(TargetId))
throw new ArgumentNullException(nameof(TargetId)); throw new ArgumentNullException(nameof(TargetId));
var stream = DocumentBulkGenerateTask.GetCached(Database, id);
return File(stream, "application/pdf", fileName);
}
// get template // get template
var template = Database.DocumentTemplates.Find(id); var template = Database.DocumentTemplates.Find(id);
@@ -18,7 +18,7 @@ namespace Disco.Web.Areas.Config.Controllers
public partial class DocumentTemplateController : AuthorizedDatabaseController public partial class DocumentTemplateController : AuthorizedDatabaseController
{ {
[DiscoAuthorize(Claims.Config.DocumentTemplate.Show)] [DiscoAuthorize(Claims.Config.DocumentTemplate.Show)]
public virtual ActionResult Index(string id) public virtual ActionResult Index(string id, string bulkGenerateId = null, string bulkGenerateFilename = null)
{ {
if (string.IsNullOrEmpty(id)) if (string.IsNullOrEmpty(id))
{ {
@@ -63,6 +63,9 @@ namespace Disco.Web.Areas.Config.Controllers
if (DocumentTemplateUsersManagedGroup.TryGetManagedGroup(m.DocumentTemplate, out usersManagedGroup)) if (DocumentTemplateUsersManagedGroup.TryGetManagedGroup(m.DocumentTemplate, out usersManagedGroup))
m.UsersLinkedGroup = usersManagedGroup; m.UsersLinkedGroup = usersManagedGroup;
m.BulkGenerateDownloadId = bulkGenerateId;
m.BulkGenerateDownloadFilename = bulkGenerateFilename;
// UI Extensions // UI Extensions
UIExtensions.ExecuteExtensions<ConfigDocumentTemplateShowModel>(this.ControllerContext, m); UIExtensions.ExecuteExtensions<ConfigDocumentTemplateShowModel>(this.ControllerContext, m);
@@ -31,6 +31,10 @@ namespace Disco.Web.Areas.Config.Models.DocumentTemplate
public DocumentTemplateDevicesManagedGroup DevicesLinkedGroup { get; set; } public DocumentTemplateDevicesManagedGroup DevicesLinkedGroup { get; set; }
public DocumentTemplateUsersManagedGroup UsersLinkedGroup { get; set; } public DocumentTemplateUsersManagedGroup UsersLinkedGroup { get; set; }
public string BulkGenerateDownloadId { get; set; }
public string BulkGenerateDownloadFilename { get; set; }
public void UpdateModel(DiscoDataContext Database) public void UpdateModel(DiscoDataContext Database)
{ {
@@ -774,103 +774,114 @@
} }
@if (canBulkGenerate) @if (canBulkGenerate)
{ {
<a id="buttonBulkGenerate" href="#" class="button">Bulk Generate</a> if (Model.DocumentTemplate.Scope == DocumentTemplate.DocumentTemplateScopes.User)
<div id="dialogBulkGenerate" class="hiddenDialog" title="Bulk Generate: @(Model.DocumentTemplate.Id)"> {
<div class="brief"> @Html.ActionLinkButton("Bulk Generate", MVC.Config.DocumentTemplate.BulkGenerate(Model.DocumentTemplate.Id))
@switch (Model.DocumentTemplate.Scope) }
else
{
<a id="buttonBulkGenerate" href="#" class="button">Bulk Generate</a>
<div id="dialogBulkGenerate" class="hiddenDialog dialog-bulk-generate" title="Bulk Generate: @(Model.DocumentTemplate.Id)">
<div class="brief">
@switch (Model.DocumentTemplate.Scope)
{
case "Device":
<div>
Enter multiple <span class="scopeDescBulkGenerate">Device Serial Numbers</span> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>).
</div>
<div class="examples clearfix">
<h4>Examples:</h4>
<div class="example1 code">
01234567<br />
ABCD9876<br />
8VQ6G2R
</div>
<div class="example2 code">01234567,ABCD9876,8VQ6G2R</div>
<div class="example3 code">01234567;ABCD9876;8VQ6G2R</div>
</div>
break;
case "Job":
<div>
Enter multiple <span class="scopeDescBulkGenerate">Job Ids</span> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>).
</div>
<div class="examples clearfix">
<h4>Examples:</h4>
<div class="example1 code">
86<br />
99<br />
44
</div>
<div class="example2 code">86,99,44</div>
<div class="example3 code">86;99;44</div>
</div>
break;
}
</div>
@using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerate(Model.DocumentTemplate.Id), FormMethod.Post))
{ {
case "Device": <div class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="DataIds"></div>
<div> <textarea id="inputBulkGenerateDataIds" name="DataIds" data-val="true" data-val-required="Identifiers are required"></textarea>
Enter multiple <span class="scopeDescBulkGenerate">Device Serial Numbers</span> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>). if (Model.TemplatePageCount > 1 && Model.TemplatePageCount % 2 != 0)
{
<div style="margin-top: 6px;">
<input id="inputBulkGenerateInsertBlankPage" type="checkbox" name="InsertBlankPage" value="True" /><label for="inputBulkGenerateInsertBlankPage">Insert Blank Pages for Double-Sided Printing</label>
</div> </div>
<div class="examples clearfix"> }
<h4>Examples:</h4>
<div class="example1 code">
01234567<br />
ABCD9876<br />
8VQ6G2R
</div>
<div class="example2 code">01234567,ABCD9876,8VQ6G2R</div>
<div class="example3 code">01234567;ABCD9876;8VQ6G2R</div>
</div>
break;
case "Job":
<div>
Enter multiple <span class="scopeDescBulkGenerate">Job Ids</span> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>).
</div>
<div class="examples clearfix">
<h4>Examples:</h4>
<div class="example1 code">
86<br />
99<br />
44
</div>
<div class="example2 code">86,99,44</div>
<div class="example3 code">86;99;44</div>
</div>
break;
case "User":
<div>
Enter multiple <span class="scopeDescBulkGenerate">User Ids</span> separated by <code>&lt;new line&gt;</code>, commas (<code>,</code>) or semicolons (<code>;</code>).
</div>
<div class="examples clearfix">
<h4>Examples:</h4>
<div class="example1 code">
user6<br />
smi0099<br />@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith
</div>
<div class="example2 code">user6,smi0099,@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith</div>
<div class="example3 code">user6;smi0099;@(ActiveDirectory.Context.PrimaryDomain.NetBiosName)\rsmith</div>
</div>
break;
} }
</div> </div>
@using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerate(Model.DocumentTemplate.Id), FormMethod.Post))
{
<div class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="DataIds"></div>
<textarea id="inputBulkGenerateDataIds" name="DataIds" data-val="true" data-val-required="Identifiers are required"></textarea>
if (Model.TemplatePageCount > 1 && Model.TemplatePageCount % 2 != 0)
{
<div style="margin-top: 6px;">
<input id="inputBulkGenerateInsertBlankPage" type="checkbox" name="InsertBlankPage" value="True" /><label for="inputBulkGenerateInsertBlankPage">Insert Blank Pages for Double-Sided Printing</label>
</div>
}
}
</div>
<script> <script>
$(function () { $(function () {
var dialog; var dialog;
$('#buttonBulkGenerate').click(function () { $('#buttonBulkGenerate').click(function () {
if (!dialog) { if (!dialog) {
dialog = $('#dialogBulkGenerate').dialog({ dialog = $('#dialogBulkGenerate').dialog({
resizable: false, resizable: false,
modal: true, modal: true,
autoOpen: false, autoOpen: false,
width: 460, width: 460,
buttons: { buttons: {
"Bulk Generate": function () { "Bulk Generate": function () {
dialog.find('form').submit(); dialog.find('form').submit();
dialog.dialog("disable"); dialog.dialog("disable");
}, },
Close: function () { Close: function () {
$(this).dialog("close"); $(this).dialog("close");
}
} }
} });
});
$.validator.unobtrusive.reparse('#inputBulkGenerateDataIds'); $.validator.unobtrusive.reparse('#inputBulkGenerateDataIds');
} }
dialog.dialog('open'); dialog.dialog('open');
return false; return false;
});
}); });
}); </script>
</script> }
} }
@if (Authorization.Has(Claims.Config.DocumentTemplate.Delete)) @if (Authorization.Has(Claims.Config.DocumentTemplate.Delete))
{ {
@Html.ActionLinkButton("Delete", MVC.API.DocumentTemplate.Delete(Model.DocumentTemplate.Id, true), "buttonDelete") @Html.ActionLinkButton("Delete", MVC.API.DocumentTemplate.Delete(Model.DocumentTemplate.Id, true), "buttonDelete")
} }
</div> </div>
@if (!string.IsNullOrWhiteSpace(Model.BulkGenerateDownloadId))
{
<div id="Config_DocumentTemplates_Show_DownloadBulk_Dialog" class="dialog" title="Download Bulk Documents">
<a href="@Url.Action(MVC.API.DocumentTemplate.BulkGenerateDownload(Model.BulkGenerateDownloadId, Model.BulkGenerateDownloadFilename))" class="button"><i class="fa fa-download fa-lg"></i>Download Bulk Documents</a>
</div>
<script>
$(function () {
$('#Config_DocumentTemplates_Show_DownloadBulk_Dialog')
.dialog({
width: 400,
height: 100,
resizable: false,
modal: true,
autoOpen: true
});
});
</script>
}