support user details category in document bulk generation

This commit is contained in:
Gary Sharp
2023-04-14 16:40:13 +10:00
parent 13549e7ec4
commit 273b67c422
10 changed files with 812 additions and 169 deletions
@@ -1113,6 +1113,60 @@ namespace Disco.Web.Areas.API.Controllers
return Json(results);
}
[DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments, Claims.User.ShowDetails)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult BulkGenerateGetUserDetailValues(string key)
{
if (string.IsNullOrWhiteSpace(key))
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
var results = Database.UserDetails.Where(d => d.Scope == "Details" && d.Key == key).Select(d => d.Value).Distinct().ToList();
return Json(results);
}
[DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments, Claims.User.ShowDetails)]
[HttpPost, ValidateAntiForgeryToken, ValidateInput(false)]
public virtual ActionResult BulkGenerateAddUserDetail(string key, string value)
{
if (string.IsNullOrWhiteSpace(key))
return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
var results = new List<BulkGenerateUserModel>();
var query = Database.UserDetails.Include(d => d.User).Where(d => d.Scope == "Details" && d.Key == key);
if (!string.IsNullOrWhiteSpace(value))
{
query = query.Where(d => d.Value == value);
}
var details = query.ToList();
if (details.Count == 0)
{
results.Add(new BulkGenerateUserModel()
{
Id = key,
DisplayName = $"{key}{(string.IsNullOrWhiteSpace(value) ? null : $":{value}")}",
Scope = $"User Detail '{key}' didn't match any users{(string.IsNullOrWhiteSpace(value) ? null : $" with the value '{value}'")}",
IsError = true,
});
} else
{
foreach (var user in details.Select(d => d.User).Distinct())
{
results.Add(new BulkGenerateUserModel()
{
Id = user.UserId,
DisplayName = user.DisplayName,
Scope = $"User Detail '{key}'{(string.IsNullOrWhiteSpace(value) ? null : $" with the value '{value}'")} Matches User",
IsError = false,
});
}
}
return Json(results);
}
public virtual ActionResult Generate(string id, string TargetId)
{
Disco.Services.DocumentTemplateExtensions.GetTemplateAndTarget(Database, Authorization, id, TargetId, out var template, out var target, out _);
@@ -12,6 +12,7 @@ using Disco.Web.Areas.Config.Models.DocumentTemplate;
using Disco.Web.Areas.Config.Views.DocumentTemplate;
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Web.Mvc;
@@ -262,6 +263,18 @@ namespace Disco.Web.Areas.Config.Controllers
throw new NotSupportedException();
}
}
if (Authorization.Has(Claims.User.ShowDetails))
{
m.UserDetails = Database.UserDetails.Where(d => d.Scope == "Details").GroupBy(d => d.Key).Select(g => new BulkGenerateModel.ItemWithCount<string>()
{
Item = g.Key,
Count = g.Count(),
}).ToList();
}
else
{
m.UserDetails = new List<BulkGenerateModel.ItemWithCount<string>>();
}
// UI Extensions
UIExtensions.ExecuteExtensions<ConfigDocumentTemplateBulkGenerate>(ControllerContext, m);
@@ -11,6 +11,7 @@ namespace Disco.Web.Areas.Config.Models.DocumentTemplate
public List<ItemWithCount<Disco.Models.Repository.DeviceProfile>> DeviceProfiles { get; set; }
public List<ItemWithCount<Disco.Models.Repository.DeviceBatch>> DeviceBatches { get; set; }
public List<ItemWithCount<Disco.Models.Repository.DocumentTemplate>> DocumentTemplates { get; set; }
public List<ItemWithCount<string>> UserDetails { get; set; }
public class ItemWithCount<T>
{
@@ -37,6 +37,10 @@
{
<button id="AddDocumentAttachment" class="button small">Add With Document Attachment</button>
}
@if (Model.UserDetails.Any(b => b.Count > 0))
{
<button id="AddUserDetail" class="button small">Add With User Detail</button>
}
</div>
<table class="genericData">
<thead>
@@ -207,3 +211,39 @@
}
</div>
}
@if (Model.UserDetails.Any(b => b.Count > 0))
{
<div id="DocumentTemplate_BulkGenerate_Dialog_AddUserDetail" class="dialog dialog-bulk-generate" title="@(Model.DocumentTemplate.Description): Add User by Detail">
<div class="brief">
<div>
Add all users with a matching user detail to the bulk generation.
</div>
</div>
@using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerateAddUserDetail(), FormMethod.Post))
{
<input name="key" type="hidden" required />
<input name="value" type="hidden" />
<div id="DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Key" class="dialog-item-picker" style="width: 49%; float: left;">
@foreach (var key in Model.UserDetails)
{
<div class="item @(key.Count == 0 ? "disabled" : null)" data-id="@key.Item">
<i class="fa fa-info fa-fw fa-lg"></i>@key.Item.TrimEnd('*', '&') <small>(@key.Count.ToString("N0") user@(key.Count == 1 ? null : "s"))</small>
</div>
}
</div>
@Html.AntiForgeryToken()
}
@using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerateGetUserDetailValues(), FormMethod.Post))
{
<input name="key" type="hidden" required />
<div id="DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Value" class="dialog-item-picker" style="width: 49%; float: left; margin-left: 1%;">
</div>
@Html.AntiForgeryToken()
}
</div>
}
File diff suppressed because it is too large Load Diff
@@ -476,4 +476,107 @@ $(() => {
return false;
});
let dialogAddUserDetail = null;
$('#AddUserDetail').click(e => {
e.preventDefault();
let dialog = dialogAddUserDetail;
if (!dialog) {
const action = delegate => {
const form = dialog.find('form')[0];
const key = $(form).find('input[name="key"]');
if (key.val()) {
if (form.reportValidity()) {
const body = new FormData(form);
fetch(form.action, {
method: 'POST',
body: body
})
.then(r => r.json())
.then(r => {
delegate(r);
key.val('');
$(form).find('input[name="value"]').val('');
$('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Value').empty();
dialog.find('div.item').removeClass('selected');
dialog.dialog("close");
dialog.dialog("enable");
})
.catch(reason => {
alert('Failed to validate user detail: ' + reason);
});
dialog.dialog("disable");
}
}
}
dialog = $('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 690,
buttons: {
"Exclude Matched Users": function () {
action(excludeUsers);
},
"Add Matched Users": function () {
action(addUsers);
}
}
});
dialogAddUserDetail = dialog;
}
const $key = dialog.find('input[name="key"]');
const $value = dialog.find('input[name="value"]');
const $keys = dialog.find('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Key');
const $values = dialog.find('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Value');
$keys.on('click', 'div.item:not(.disabled)', e => {
e.preventDefault();
const $target = $(e.currentTarget);
const keyValue = $target.attr('data-id');
$key.val(keyValue);
$keys.find('div.item').removeClass('selected');
$target.addClass('selected');
$values.empty();
$values.append($('<i class="ajaxLoading" title="Loading"></i>'));
const form = dialog.find('form')[1];
const body = new FormData(form);
fetch(form.action, {
method: 'POST',
body: body
})
.then(r => r.json())
.then(r => {
$values.empty();
const allValues = $('<div class="item selected" data-id=""><i class="fa fa-info fa-fw fa-lg"></i><em>All Matched Users</em></div>');
allValues.appendTo($values);
$value.val('');
r.map(v => {
const container = $('<div class="item"><i class="fa fa-info fa-fw fa-lg"></i ></div>');
container.attr('data-id', v);
const span = $('<span>').text(v);
span.appendTo(container);
container.appendTo($values);
})
})
.catch(reason => {
alert('Failed to validate user detail: ' + reason);
});
dialog.dialog("disable");
return false;
});
$values.on('click', 'div.item:not(.disabled)', e => {
e.preventDefault();
const $target = $(e.currentTarget);
$value.val($target.attr('data-id'));
$values.find('div.item').removeClass('selected');
$target.addClass('selected');
});
dialog.dialog('open');
return false;
});
});
File diff suppressed because one or more lines are too long
@@ -476,4 +476,107 @@
return false;
});
let dialogAddUserDetail = null;
$('#AddUserDetail').click(e => {
e.preventDefault();
let dialog = dialogAddUserDetail;
if (!dialog) {
const action = delegate => {
const form = dialog.find('form')[0];
const key = $(form).find('input[name="key"]');
if (key.val()) {
if (form.reportValidity()) {
const body = new FormData(form);
fetch(form.action, {
method: 'POST',
body: body
})
.then(r => r.json())
.then(r => {
delegate(r);
key.val('');
$(form).find('input[name="value"]').val('');
$('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Value').empty();
dialog.find('div.item').removeClass('selected');
dialog.dialog("close");
dialog.dialog("enable");
})
.catch(reason => {
alert('Failed to validate user detail: ' + reason);
});
dialog.dialog("disable");
}
}
}
dialog = $('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail').dialog({
resizable: false,
modal: true,
autoOpen: false,
width: 690,
buttons: {
"Exclude Matched Users": function () {
action(excludeUsers);
},
"Add Matched Users": function () {
action(addUsers);
}
}
});
dialogAddUserDetail = dialog;
}
const $key = dialog.find('input[name="key"]');
const $value = dialog.find('input[name="value"]');
const $keys = dialog.find('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Key');
const $values = dialog.find('#DocumentTemplate_BulkGenerate_Dialog_AddUserDetail_Value');
$keys.on('click', 'div.item:not(.disabled)', e => {
e.preventDefault();
const $target = $(e.currentTarget);
const keyValue = $target.attr('data-id');
$key.val(keyValue);
$keys.find('div.item').removeClass('selected');
$target.addClass('selected');
$values.empty();
$values.append($('<i class="ajaxLoading" title="Loading"></i>'));
const form = dialog.find('form')[1];
const body = new FormData(form);
fetch(form.action, {
method: 'POST',
body: body
})
.then(r => r.json())
.then(r => {
$values.empty();
const allValues = $('<div class="item selected" data-id=""><i class="fa fa-info fa-fw fa-lg"></i><em>All Matched Users</em></div>');
allValues.appendTo($values);
$value.val('');
r.map(v => {
const container = $('<div class="item"><i class="fa fa-info fa-fw fa-lg"></i ></div>');
container.attr('data-id', v);
const span = $('<span>').text(v);
span.appendTo(container);
container.appendTo($values);
})
})
.catch(reason => {
alert('Failed to validate user detail: ' + reason);
});
dialog.dialog("disable");
return false;
});
$values.on('click', 'div.item:not(.disabled)', e => {
e.preventDefault();
const $target = $(e.currentTarget);
$value.val($target.attr('data-id'));
$values.find('div.item').removeClass('selected');
$target.addClass('selected');
});
dialog.dialog('open');
return false;
});
});
@@ -217,6 +217,18 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult BulkGenerateGetUserDetailValues()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.BulkGenerateGetUserDetailValues);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult BulkGenerateAddUserDetail()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.BulkGenerateAddUserDetail);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Generate()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Generate);
@@ -282,6 +294,8 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string BulkGenerateAddDeviceProfile = "BulkGenerateAddDeviceProfile";
public readonly string BulkGenerateAddDeviceBatch = "BulkGenerateAddDeviceBatch";
public readonly string BulkGenerateAddDocumentAttachment = "BulkGenerateAddDocumentAttachment";
public readonly string BulkGenerateGetUserDetailValues = "BulkGenerateGetUserDetailValues";
public readonly string BulkGenerateAddUserDetail = "BulkGenerateAddUserDetail";
public readonly string Generate = "Generate";
public readonly string Delete = "Delete";
public readonly string GenerateDocumentHandlerUi = "GenerateDocumentHandlerUi";
@@ -318,6 +332,8 @@ namespace Disco.Web.Areas.API.Controllers
public const string BulkGenerateAddDeviceProfile = "BulkGenerateAddDeviceProfile";
public const string BulkGenerateAddDeviceBatch = "BulkGenerateAddDeviceBatch";
public const string BulkGenerateAddDocumentAttachment = "BulkGenerateAddDocumentAttachment";
public const string BulkGenerateGetUserDetailValues = "BulkGenerateGetUserDetailValues";
public const string BulkGenerateAddUserDetail = "BulkGenerateAddUserDetail";
public const string Generate = "Generate";
public const string Delete = "Delete";
public const string GenerateDocumentHandlerUi = "GenerateDocumentHandlerUi";
@@ -571,6 +587,23 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string documentTemplateId = "documentTemplateId";
public readonly string threshold = "threshold";
}
static readonly ActionParamsClass_BulkGenerateGetUserDetailValues s_params_BulkGenerateGetUserDetailValues = new ActionParamsClass_BulkGenerateGetUserDetailValues();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_BulkGenerateGetUserDetailValues BulkGenerateGetUserDetailValuesParams { get { return s_params_BulkGenerateGetUserDetailValues; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_BulkGenerateGetUserDetailValues
{
public readonly string key = "key";
}
static readonly ActionParamsClass_BulkGenerateAddUserDetail s_params_BulkGenerateAddUserDetail = new ActionParamsClass_BulkGenerateAddUserDetail();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_BulkGenerateAddUserDetail BulkGenerateAddUserDetailParams { get { return s_params_BulkGenerateAddUserDetail; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_BulkGenerateAddUserDetail
{
public readonly string key = "key";
public readonly string value = "value";
}
static readonly ActionParamsClass_Generate s_params_Generate = new ActionParamsClass_Generate();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Generate GenerateParams { get { return s_params_Generate; } }
@@ -1000,6 +1033,31 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
[NonAction]
partial void BulkGenerateGetUserDetailValuesOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string key);
[NonAction]
public override System.Web.Mvc.ActionResult BulkGenerateGetUserDetailValues(string key)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.BulkGenerateGetUserDetailValues);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "key", key);
BulkGenerateGetUserDetailValuesOverride(callInfo, key);
return callInfo;
}
[NonAction]
partial void BulkGenerateAddUserDetailOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string key, string value);
[NonAction]
public override System.Web.Mvc.ActionResult BulkGenerateAddUserDetail(string key, string value)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.BulkGenerateAddUserDetail);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "key", key);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "value", value);
BulkGenerateAddUserDetailOverride(callInfo, key, value);
return callInfo;
}
[NonAction]
partial void GenerateOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string TargetId);
+2 -8
View File
@@ -176,10 +176,7 @@ namespace Links
public static readonly string livestamp_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/livestamp.min.js") ? Url("livestamp.min.js") : Url("livestamp.js");
public static readonly string livestamp_js_ = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/livestamp.min.js") ? Url("livestamp.min.js") : Url("livestamp.js");
public static readonly string modernizr_2_7_2_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/modernizr-2.7.2.min.js") ? Url("modernizr-2.7.2.min.js") : Url("modernizr-2.7.2.js");
public static readonly string moment_en_au_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/moment.en-au.min.js") ? Url("moment.en-au.min.js") : Url("moment.en-au.js");
public static readonly string moment_en_au_js_ = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/moment.en-au.min.js") ? Url("moment.en-au.min.js") : Url("moment.en-au.js");
public static readonly string moment_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/moment.min.js") ? Url("moment.min.js") : Url("moment.js");
public static readonly string moment_js_ = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/moment.min.js") ? Url("moment.min.js") : Url("moment.js");
public static readonly string moment_with_locales_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/moment-with-locales.min.js") ? Url("moment-with-locales.min.js") : Url("moment-with-locales.js");
}
public static readonly string Core_js = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(UrlPath + "/Core.min.js") ? Url("Core.min.js") : Url("Core.js");
@@ -915,10 +912,7 @@ namespace Links
public const string livestamp_js = "~/ClientSource/Scripts/Core/livestamp.js";
public const string livestamp_js_ = "~/ClientSource/Scripts/Core/livestamp.js";
public const string modernizr_2_7_2_js = "~/ClientSource/Scripts/Core/modernizr-2.7.2.js";
public const string moment_en_au_js = "~/ClientSource/Scripts/Core/moment.en-au.js";
public const string moment_en_au_js_ = "~/ClientSource/Scripts/Core/moment.en-au.js";
public const string moment_js = "~/ClientSource/Scripts/Core/moment.js";
public const string moment_js_ = "~/ClientSource/Scripts/Core/moment.js";
public const string moment_with_locales_js = "~/ClientSource/Scripts/Core/moment-with-locales.js";
}
}
public static partial class Modules