From ca7193a8fc8f771763cfbb120f6ca87cd9dc2be1 Mon Sep 17 00:00:00 2001 From: Gary Sharp Date: Sun, 17 Aug 2025 18:22:03 +1000 Subject: [PATCH] feature: device document template bulk generation --- .../Interop/WIMInterop.cs | 1 - Disco.Models/Repository/Device/Device.cs | 1 - .../Repository/Device/Flag/DeviceFlag.cs | 3 +- Disco.Models/Repository/User/Flag/UserFlag.cs | 3 +- .../ConfigDocumentTemplateBulkGenerate.cs | 11 +- .../DeviceFlags/DeviceFlagExtensions.cs | 1 - .../Documents/DocumentTemplatePackages.cs | 1 - Disco.Services/Plugins/InstallPluginTask.cs | 1 - .../Users/UserFlags/UserFlagExtensions.cs | 1 - .../OrganisationAddressExtensions.cs | 1 - .../API/Controllers/DeviceFlagController.cs | 1 - .../Controllers/DocumentTemplateController.cs | 853 ++++++-- .../UserFlagAssignmentController.cs | 1 - ...eUserModel.cs => BulkGenerateItemModel.cs} | 6 +- .../Controllers/DeviceBatchController.cs | 1 - .../Controllers/DeviceFlagController.cs | 1 - .../Controllers/DocumentTemplateController.cs | 176 +- .../Config/Controllers/JobQueueController.cs | 3 +- .../DocumentTemplate/BulkGenerateModel.cs | 13 +- .../BulkGenerate.generated.cs | 1558 ------------- .../BulkGenerateDevice.cshtml | 61 + .../BulkGenerateDevice.generated.cs | 332 +++ .../DocumentTemplate/BulkGenerateUser.cshtml | 62 + .../BulkGenerateUser.generated.cs | 332 +++ .../Config/Views/DocumentTemplate/Show.cshtml | 2 +- .../Views/DocumentTemplate/Show.generated.cs | 18 +- ...rate.cshtml => _BulkGenerateShared.cshtml} | 273 ++- .../_BulkGenerateShared.generated.cs | 1943 +++++++++++++++++ .../Modules/Disco-DocumentBulkGenerate.js | 505 +++-- .../Modules/Disco-DocumentBulkGenerate.min.js | 2 +- .../disco.documentbulkgenerate.js | 505 +++-- Disco.Web/ClientSource/Style/Config.css | 7 +- Disco.Web/ClientSource/Style/Config.less | 18 +- Disco.Web/ClientSource/Style/Config.min.css | 2 +- Disco.Web/Disco.Web.csproj | 28 +- ...PI.DocumentTemplateController.generated.cs | 96 +- ...ig.DocumentTemplateController.generated.cs | 8 +- Disco.Web/Extensions/T4MVC/T4MVC.cs | 34 +- Disco.Web/packages.config | 1 - 39 files changed, 4437 insertions(+), 2429 deletions(-) rename Disco.Web/Areas/API/Models/DocumentTemplate/{BulkGenerateUserModel.cs => BulkGenerateItemModel.cs} (72%) delete mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerate.generated.cs create mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerateDevice.cshtml create mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerateDevice.generated.cs create mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerateUser.cshtml create mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerateUser.generated.cs rename Disco.Web/Areas/Config/Views/DocumentTemplate/{BulkGenerate.cshtml => _BulkGenerateShared.cshtml} (51%) create mode 100644 Disco.Web/Areas/Config/Views/DocumentTemplate/_BulkGenerateShared.generated.cs diff --git a/Disco.ClientBootstrapper/Interop/WIMInterop.cs b/Disco.ClientBootstrapper/Interop/WIMInterop.cs index 0212e13c..34dd198e 100644 --- a/Disco.ClientBootstrapper/Interop/WIMInterop.cs +++ b/Disco.ClientBootstrapper/Interop/WIMInterop.cs @@ -1,6 +1,5 @@ using System; using System.Collections; -using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Text; diff --git a/Disco.Models/Repository/Device/Device.cs b/Disco.Models/Repository/Device/Device.cs index 5299c248..f0afe1c7 100644 --- a/Disco.Models/Repository/Device/Device.cs +++ b/Disco.Models/Repository/Device/Device.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; -using System.Linq; namespace Disco.Models.Repository { diff --git a/Disco.Models/Repository/Device/Flag/DeviceFlag.cs b/Disco.Models/Repository/Device/Flag/DeviceFlag.cs index 120bc999..8ab90082 100644 --- a/Disco.Models/Repository/Device/Flag/DeviceFlag.cs +++ b/Disco.Models/Repository/Device/Flag/DeviceFlag.cs @@ -1,5 +1,4 @@ -using Disco.Models.Services.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; diff --git a/Disco.Models/Repository/User/Flag/UserFlag.cs b/Disco.Models/Repository/User/Flag/UserFlag.cs index 859439e0..022c7068 100644 --- a/Disco.Models/Repository/User/Flag/UserFlag.cs +++ b/Disco.Models/Repository/User/Flag/UserFlag.cs @@ -1,5 +1,4 @@ -using Disco.Models.Services.Authorization; -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; diff --git a/Disco.Models/UI/Config/DocumentTemplate/ConfigDocumentTemplateBulkGenerate.cs b/Disco.Models/UI/Config/DocumentTemplate/ConfigDocumentTemplateBulkGenerate.cs index 940efd48..374a1d10 100644 --- a/Disco.Models/UI/Config/DocumentTemplate/ConfigDocumentTemplateBulkGenerate.cs +++ b/Disco.Models/UI/Config/DocumentTemplate/ConfigDocumentTemplateBulkGenerate.cs @@ -7,13 +7,22 @@ namespace Disco.Models.UI.Config.DocumentTemplate Repository.DocumentTemplate DocumentTemplate { get; set; } int TemplatePageCount { get; set; } - List> UserFlags { get; set; } List> DeviceProfiles { get; set; } List> DeviceBatches { get; set; } List> DocumentTemplates { get; set; } List> UserDetails { get; set; } } + public interface ConfigDocumentTemplateBulkGenerateUser : ConfigDocumentTemplateBulkGenerate + { + List> UserFlags { get; set; } + } + + public interface ConfigDocumentTemplateBulkGenerateDevice : ConfigDocumentTemplateBulkGenerate + { + List> DeviceFlags { get; set; } + } + public class ItemWithCount { public T Item { get; set; } diff --git a/Disco.Services/Devices/DeviceFlags/DeviceFlagExtensions.cs b/Disco.Services/Devices/DeviceFlags/DeviceFlagExtensions.cs index b1aebbd3..bc5464bc 100644 --- a/Disco.Services/Devices/DeviceFlags/DeviceFlagExtensions.cs +++ b/Disco.Services/Devices/DeviceFlags/DeviceFlagExtensions.cs @@ -1,6 +1,5 @@ using Disco.Data.Repository; using Disco.Models.Repository; -using Disco.Services.Authorization; using Disco.Services.Devices.DeviceFlags; using Disco.Services.Expressions; using Disco.Services.Logging; diff --git a/Disco.Services/Documents/DocumentTemplatePackages.cs b/Disco.Services/Documents/DocumentTemplatePackages.cs index 0eb9b3e8..3f3b5870 100644 --- a/Disco.Services/Documents/DocumentTemplatePackages.cs +++ b/Disco.Services/Documents/DocumentTemplatePackages.cs @@ -1,7 +1,6 @@ using Disco.Data.Repository; using Disco.Models.Repository; using Disco.Models.Services.Documents; -using Disco.Models.UI.Config.DocumentTemplate; using System; using System.Collections.Concurrent; using System.Collections.Generic; diff --git a/Disco.Services/Plugins/InstallPluginTask.cs b/Disco.Services/Plugins/InstallPluginTask.cs index 9ca76f5f..d4f27f80 100644 --- a/Disco.Services/Plugins/InstallPluginTask.cs +++ b/Disco.Services/Plugins/InstallPluginTask.cs @@ -1,5 +1,4 @@ using Disco.Data.Repository; -using Disco.Models.Services.Interop.DiscoServices; using Disco.Services.Interop.DiscoServices; using Disco.Services.Tasks; using Quartz; diff --git a/Disco.Services/Users/UserFlags/UserFlagExtensions.cs b/Disco.Services/Users/UserFlags/UserFlagExtensions.cs index 60221600..ba5be1cd 100644 --- a/Disco.Services/Users/UserFlags/UserFlagExtensions.cs +++ b/Disco.Services/Users/UserFlags/UserFlagExtensions.cs @@ -1,6 +1,5 @@ using Disco.Data.Repository; using Disco.Models.Repository; -using Disco.Services.Authorization; using Disco.Services.Expressions; using Disco.Services.Logging; using Disco.Services.Users; diff --git a/Disco.Web.Extensions/BIModelExtensions/OrganisationAddressExtensions.cs b/Disco.Web.Extensions/BIModelExtensions/OrganisationAddressExtensions.cs index b909761b..2c2ee606 100644 --- a/Disco.Web.Extensions/BIModelExtensions/OrganisationAddressExtensions.cs +++ b/Disco.Web.Extensions/BIModelExtensions/OrganisationAddressExtensions.cs @@ -1,5 +1,4 @@ using Disco.Models.BI.Config; -using System; using System.Collections.Generic; using System.Linq; using System.Web.Mvc; diff --git a/Disco.Web/Areas/API/Controllers/DeviceFlagController.cs b/Disco.Web/Areas/API/Controllers/DeviceFlagController.cs index 49ca7e7f..3f4a5fad 100644 --- a/Disco.Web/Areas/API/Controllers/DeviceFlagController.cs +++ b/Disco.Web/Areas/API/Controllers/DeviceFlagController.cs @@ -5,7 +5,6 @@ using Disco.Services.Devices.DeviceFlags; using Disco.Services.Exporting; using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Tasks; -using Disco.Services.Users.UserFlags; using Disco.Services.Web; using Disco.Web.Areas.API.Models.Shared; using Disco.Web.Areas.Config.Models.DeviceFlag; diff --git a/Disco.Web/Areas/API/Controllers/DocumentTemplateController.cs b/Disco.Web/Areas/API/Controllers/DocumentTemplateController.cs index 55c7eef6..41b64991 100644 --- a/Disco.Web/Areas/API/Controllers/DocumentTemplateController.cs +++ b/Disco.Web/Areas/API/Controllers/DocumentTemplateController.cs @@ -31,13 +31,13 @@ namespace Disco.Web.Areas.API.Controllers public partial class DocumentTemplateController : AuthorizedDatabaseController { - const string pDescription = "description"; - const string pScope = "scope"; - const string pFilterExpression = "filterexpression"; - const string pOnGenerateExpression = "ongenerateexpression"; - const string pOnImportAttachmentExpression = "onimportattachmentexpression"; - const string pFlattenForm = "flattenform"; - const string pIsHidden = "ishidden"; + private const string pDescription = "description"; + private const string pScope = "scope"; + private const string pFilterExpression = "filterexpression"; + private const string pOnGenerateExpression = "ongenerateexpression"; + private const string pOnImportAttachmentExpression = "onimportattachmentexpression"; + private const string pFlattenForm = "flattenform"; + private const string pIsHidden = "ishidden"; [DiscoAuthorize(Claims.Config.DocumentTemplate.Configure)] [HttpPost, ValidateAntiForgeryToken] @@ -841,26 +841,49 @@ namespace Disco.Web.Areas.API.Controllers return File(stream, "application/pdf", fileName); } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments)] - [HttpPost, ValidateAntiForgeryToken] - public virtual ActionResult BulkGenerateAddUsers(string userIds) + private List BulkGenerateEvaluateScope(string scope, T arg, Func> userScope, Func> deviceScope) { - if (string.IsNullOrWhiteSpace(userIds)) + if (string.IsNullOrWhiteSpace(scope)) + throw new ArgumentNullException(nameof(scope), "Scope is required."); + + if ("user".Equals(scope, StringComparison.OrdinalIgnoreCase)) + return userScope(arg); + else if ("device".Equals(scope, StringComparison.OrdinalIgnoreCase)) + return deviceScope(arg); + else + throw new ArgumentException("Invalid scope specified. Use 'user' or 'device'.", nameof(scope)); + } + + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] + [HttpPost, ValidateAntiForgeryToken] + public virtual ActionResult BulkGenerateAddUsers(string scope, string userIds) + { + if (string.IsNullOrWhiteSpace(scope) || string.IsNullOrWhiteSpace(userIds)) return BadRequest(); var dataIds = userIds.Split(new string[] { Environment.NewLine, ",", ";" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).Where(d => !string.IsNullOrEmpty(d)).ToList(); - var results = new List(dataIds.Count); + + if (dataIds.Count == 0) + return Json(new List()); + + var results = BulkGenerateEvaluateScope(scope, dataIds, BulkGenerateUserAddUsers, BulkGenerateDeviceAddUsers); + + return Json(results); + } + private List BulkGenerateUserAddUsers(List dataIds) + { + var results = new List(dataIds.Count); foreach (var dataId in dataIds) { var accountId = ActiveDirectory.ParseDomainAccountId(dataId); if (UserService.TryGetUser(accountId, Database, true, out var user)) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = user.UserId, UserEmailAddress = user.EmailAddress, - DisplayName = user.DisplayName, + UserDisplayName = user.DisplayName, Scope = $"Matched '{dataId}'", IsError = false, }); @@ -872,10 +895,10 @@ namespace Disco.Web.Areas.API.Controllers if (adObject == null) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = dataId, - DisplayName = dataId, + UserDisplayName = dataId, Scope = $"Unknown User or Security Group '{dataId}'", IsError = true, }); @@ -886,10 +909,10 @@ namespace Disco.Web.Areas.API.Controllers { foreach (var adUser in group.GetUserMembersRecursive()) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = adUser.Id, - DisplayName = adUser.DisplayName, + UserDisplayName = adUser.DisplayName, UserEmailAddress = adUser.Email, Scope = $"Group Member '{group.Name}'", IsError = false, @@ -899,10 +922,10 @@ namespace Disco.Web.Areas.API.Controllers } else { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = dataId, - DisplayName = dataId, + UserDisplayName = dataId, Scope = $"Unexpected AD Object found at '{adObject.DistinguishedName}'", IsError = true, }); @@ -910,6 +933,88 @@ namespace Disco.Web.Areas.API.Controllers } } } + return results; + } + private List BulkGenerateDeviceAddUsers(List dataIds) + { + var results = new List(dataIds.Count); + foreach (var dataId in dataIds) + { + var accountId = ActiveDirectory.ParseDomainAccountId(dataId); + var dbUser = Database.Users + .Include(u => u.DeviceUserAssignments) + .Where(u => u.UserId == accountId) + .FirstOrDefault(); + + if (dbUser != null) + { + var assignments = dbUser.CurrentDeviceAssignments; + + if (assignments.Any()) + { + if (UserService.TryGetUser(accountId, Database, true, out var adUser)) + dbUser = adUser; // use updated user from AD + foreach (var assignment in assignments) + { + results.Add(new BulkGenerateItemModel() + { + Id = assignment.DeviceSerialNumber, + UserEmailAddress = dbUser.EmailAddress, + UserDisplayName = dbUser.DisplayName, + Scope = $"Matched assigned user '{dataId}'", + IsError = false, + }); + } + } + } + } + return results; + } + + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.Device.Actions.GenerateDocuments)] + [HttpPost, ValidateAntiForgeryToken] + public virtual ActionResult BulkGenerateAddDevices(string deviceSerialNumbers) + { + if (string.IsNullOrWhiteSpace(deviceSerialNumbers)) + return BadRequest(); + + var dataIds = deviceSerialNumbers.Split(new string[] { Environment.NewLine, ",", ";" }, StringSplitOptions.RemoveEmptyEntries).Select(d => d.Trim()).Where(d => !string.IsNullOrEmpty(d)).ToList(); + + if (dataIds.Count == 0) + return Json(new List()); + + var results = new List(); + + var devices = Database.Devices.Include(d => d.AssignedUser).Where(d => dataIds.Contains(d.SerialNumber)).ToDictionary(d => d.SerialNumber, StringComparer.OrdinalIgnoreCase); + + foreach (var deviceSerialNumber in dataIds) + { + if (devices.TryGetValue(deviceSerialNumber, out var device)) + { + var user = device.AssignedUser; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = device.SerialNumber, + UserEmailAddress = user?.EmailAddress, + UserDisplayName = user?.DisplayName, + Scope = $"Matched '{deviceSerialNumber}'", + IsError = false, + }); + } + else + { + results.Add(new BulkGenerateItemModel() + { + Id = deviceSerialNumber, + UserDisplayName = deviceSerialNumber, + Scope = $"Unknown Device '{deviceSerialNumber}'", + IsError = true, + }); + } + } return Json(results); } @@ -921,17 +1026,17 @@ namespace Disco.Web.Areas.API.Controllers if (string.IsNullOrWhiteSpace(groupId)) return BadRequest(); - var results = new List(); + var results = new List(); var accountId = ActiveDirectory.ParseDomainAccountId(groupId); var adObject = ActiveDirectory.RetrieveADObject(accountId, true); if (adObject == null) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = groupId, - DisplayName = groupId, + UserDisplayName = groupId, Scope = $"Unknown Security Group '{groupId}'", IsError = true, }); @@ -940,10 +1045,10 @@ namespace Disco.Web.Areas.API.Controllers { foreach (var adUser in group.GetUserMembersRecursive()) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = adUser.Id, - DisplayName = adUser.DisplayName, + UserDisplayName = adUser.DisplayName, UserEmailAddress = adUser.Email, Scope = $"Group Member '{group.Name}'", IsError = false, @@ -952,10 +1057,10 @@ namespace Disco.Web.Areas.API.Controllers } else if (adObject is ADUserAccount user) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = user.Id, - DisplayName = user.DisplayName, + UserDisplayName = user.DisplayName, UserEmailAddress = user.Email, Scope = $"Matched '{groupId}'", IsError = false, @@ -963,10 +1068,10 @@ namespace Disco.Web.Areas.API.Controllers } else { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = groupId, - DisplayName = groupId, + UserDisplayName = groupId, Scope = $"Unexpected AD Object found at '{adObject.DistinguishedName}'", IsError = true, }); @@ -982,16 +1087,16 @@ namespace Disco.Web.Areas.API.Controllers if (flagId <= 0) return BadRequest(); - var results = new List(); + var results = new List(); var flag = Database.UserFlags.Include(f => f.UserFlagAssignments.Select(a => a.User)).FirstOrDefault(f => f.Id == flagId); if (flag == null) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = flagId.ToString(), - DisplayName = flagId.ToString(), + UserDisplayName = flagId.ToString(), Scope = $"Unknown User Flag '{flagId}'", IsError = true, }); @@ -1002,10 +1107,10 @@ namespace Disco.Web.Areas.API.Controllers if (assignments.Count == 0) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = flag.Name, - DisplayName = flag.Name, + UserDisplayName = flag.Name, Scope = $"User Flag has no active assignments", IsError = true, }); @@ -1014,11 +1119,15 @@ namespace Disco.Web.Areas.API.Controllers { foreach (var assignment in assignments) { - results.Add(new BulkGenerateUserModel() + var user = assignment.User; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { Id = assignment.UserId, - UserEmailAddress = assignment.User.EmailAddress, - DisplayName = assignment.User.DisplayName, + UserEmailAddress = user?.EmailAddress, + UserDisplayName = user?.DisplayName, Scope = $"Assigned User Flag '{flag.Name}'", IsError = false, }); @@ -1029,228 +1138,501 @@ namespace Disco.Web.Areas.API.Controllers return Json(results); } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments)] + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] [HttpPost, ValidateAntiForgeryToken] - public virtual ActionResult BulkGenerateAddDeviceProfile(int deviceProfileId) + public virtual ActionResult BulkGenerateAddDeviceFlag(int flagId) { - if (deviceProfileId <= 0) + if (flagId <= 0) return BadRequest(); - var results = new List(); + var results = new List(); + + var flag = Database.DeviceFlags.Include(f => f.DeviceFlagAssignments.Select(a => a.Device.AssignedUser)).FirstOrDefault(f => f.Id == flagId); + + if (flag == null) + { + results.Add(new BulkGenerateItemModel() + { + Id = flagId.ToString(), + UserDisplayName = flagId.ToString(), + Scope = $"Unknown User Flag '{flagId}'", + IsError = true, + }); + } + else + { + var assignments = flag.DeviceFlagAssignments.Where(a => a.RemovedDate == null).ToList(); + + if (assignments.Count == 0) + { + results.Add(new BulkGenerateItemModel() + { + Id = flag.Name, + UserDisplayName = flag.Name, + Scope = $"Device Flag has no active assignments", + IsError = true, + }); + } + else + { + foreach (var assignment in assignments) + { + var user = assignment.Device.AssignedUser; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.DeviceSerialNumber, + UserEmailAddress = user?.EmailAddress, + UserDisplayName = user?.DisplayName, + Scope = $"Assigned User Flag '{flag.Name}'", + IsError = false, + }); + } + } + } + + return Json(results); + } + + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] + [HttpPost, ValidateAntiForgeryToken] + public virtual ActionResult BulkGenerateAddDeviceProfile(string scope, int deviceProfileId) + { + if (string.IsNullOrWhiteSpace(scope) && deviceProfileId <= 0) + return BadRequest(); var profile = Database.DeviceProfiles.Include(p => p.Devices.Select(a => a.AssignedUser)).FirstOrDefault(f => f.Id == deviceProfileId); if (profile == null) { - results.Add(new BulkGenerateUserModel() + var result = new List() { + new BulkGenerateItemModel() + { + Id = deviceProfileId.ToString(), + UserDisplayName = deviceProfileId.ToString(), + Scope = $"Unknown Device Profile '{deviceProfileId}'", + IsError = true, + } + }; + return Json(result); + } + + var results = BulkGenerateEvaluateScope(scope, profile, BulkGenerateUserAddDeviceProfile, BulkGenerateDeviceAddDeviceProfile); + + return Json(results); + } + private List BulkGenerateUserAddDeviceProfile(DeviceProfile profile) + { + var results = new List(); + + var assignments = profile.Devices.Where(d => d.AssignedUser != null).ToList(); + + if (assignments.Count == 0) + { + results.Add(new BulkGenerateItemModel() { - Id = deviceProfileId.ToString(), - DisplayName = deviceProfileId.ToString(), - Scope = $"Unknown Device Profile '{deviceProfileId}'", + Id = profile.Name, + UserDisplayName = profile.Name, + Scope = $"Device Profile has no devices with active assignments", IsError = true, }); } else { - var assignments = profile.Devices.Where(d => d.AssignedUser != null).ToList(); - - if (assignments.Count == 0) + foreach (var assignment in assignments) { - results.Add(new BulkGenerateUserModel() + var user = assignment.AssignedUser; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { - Id = profile.Name, - DisplayName = profile.Name, - Scope = $"Device Profile has no devices with active assignments", - IsError = true, + Id = user.UserId, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Device Profile '{profile.Name}' Matches Assigned Device '{assignment.SerialNumber}'", + IsError = false, }); } - else + } + return results; + } + private List BulkGenerateDeviceAddDeviceProfile(DeviceProfile profile) + { + var results = new List(); + + if (profile.Devices.Count == 0) + { + results.Add(new BulkGenerateItemModel() { - foreach (var assignment in assignments) + Id = profile.Name, + UserDisplayName = profile.Name, + Scope = $"Device Profile has no devices", + IsError = true, + }); + } + else + { + foreach (var device in profile.Devices) + { + var user = device.AssignedUser; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { - results.Add(new BulkGenerateUserModel() - { - Id = assignment.AssignedUserId, - DisplayName = assignment.AssignedUser.DisplayName, - UserEmailAddress = assignment.AssignedUser.EmailAddress, - Scope = $"Device Profile '{profile.Name}' Matches Assigned Device '{assignment.SerialNumber}'", - IsError = false, - }); - } + Id = device.SerialNumber, + UserDisplayName = user?.DisplayName, + UserEmailAddress = user?.EmailAddress, + Scope = $"Device Profile '{profile.Name}'", + IsError = false, + }); } } - - return Json(results); + return results; } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments)] + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] [HttpPost, ValidateAntiForgeryToken] - public virtual ActionResult BulkGenerateAddDeviceBatch(int deviceBatchId) + public virtual ActionResult BulkGenerateAddDeviceBatch(string scope, int deviceBatchId) { if (deviceBatchId <= 0) return BadRequest(); - var results = new List(); - var batch = Database.DeviceBatches.Include(p => p.Devices.Select(a => a.AssignedUser)).FirstOrDefault(f => f.Id == deviceBatchId); if (batch == null) { - results.Add(new BulkGenerateUserModel() + var result = new List() { - Id = deviceBatchId.ToString(), - DisplayName = deviceBatchId.ToString(), - Scope = $"Unknown Device Batch '{deviceBatchId}'", + new BulkGenerateItemModel() + { + Id = deviceBatchId.ToString(), + UserDisplayName = deviceBatchId.ToString(), + Scope = $"Unknown Device Batch '{deviceBatchId}'", + IsError = true, + } + }; + return Json(result); + } + + var results = BulkGenerateEvaluateScope(scope, batch, BulkGenerateUserAddDeviceBatch, BulkGenerateDeviceAddDeviceBatch); + + return Json(results); + } + private List BulkGenerateUserAddDeviceBatch(DeviceBatch batch) + { + var assignments = batch.Devices.Where(d => d.AssignedUser != null).ToList(); + var results = new List(); + if (assignments.Count == 0) + { + results.Add(new BulkGenerateItemModel() + { + Id = batch.Name, + UserDisplayName = batch.Name, + Scope = $"Device Batch has no devices with active assignments", IsError = true, }); } else { - var assignments = batch.Devices.Where(d => d.AssignedUser != null).ToList(); - - if (assignments.Count == 0) + foreach (var assignment in assignments) { - results.Add(new BulkGenerateUserModel() + var user = assignment.AssignedUser; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { - Id = batch.Name, - DisplayName = batch.Name, - Scope = $"Device Batch has no devices with active assignments", - IsError = true, + Id = assignment.AssignedUserId, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Device Batch '{batch.Name}' Matches Assigned Device '{assignment.SerialNumber}'", + IsError = false, }); } - else + } + return results; + } + private List BulkGenerateDeviceAddDeviceBatch(DeviceBatch batch) + { + var results = new List(); + if (batch.Devices.Count == 0) + { + results.Add(new BulkGenerateItemModel() { - foreach (var assignment in assignments) + Id = batch.Name, + UserDisplayName = batch.Name, + Scope = $"Device Batch has no devices", + IsError = true, + }); + } + else + { + foreach (var device in batch.Devices) + { + var user = device.AssignedUser; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { - results.Add(new BulkGenerateUserModel() - { - Id = assignment.AssignedUserId, - DisplayName = assignment.AssignedUser.DisplayName, - UserEmailAddress = assignment.AssignedUser.EmailAddress, - Scope = $"Device Batch '{batch.Name}' Matches Assigned Device '{assignment.SerialNumber}'", - IsError = false, - }); - } + Id = device.SerialNumber, + UserDisplayName = user?.DisplayName, + UserEmailAddress = user?.EmailAddress, + Scope = $"Device Batch '{batch.Name}'", + IsError = false, + }); } } - - return Json(results); + return results; } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments)] + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] [HttpPost, ValidateAntiForgeryToken] - public virtual ActionResult BulkGenerateAddDocumentAttachment(string documentTemplateId, DateTime? threshold) + public virtual ActionResult BulkGenerateAddDocumentAttachment(string scope, string documentTemplateId, DateTime? threshold) { if (string.IsNullOrWhiteSpace(documentTemplateId)) return BadRequest(); - var results = new List(); - var template = Database.DocumentTemplates.FirstOrDefault(f => f.Id == documentTemplateId); if (template == null) { - results.Add(new BulkGenerateUserModel() + var result = new List() { - Id = documentTemplateId, - DisplayName = documentTemplateId, - Scope = $"Unknown Document Template '{documentTemplateId}'", - IsError = true, - }); + new BulkGenerateItemModel() + { + Id = documentTemplateId, + UserDisplayName = documentTemplateId, + Scope = $"Unknown Document Template '{documentTemplateId}'", + IsError = true, + } + }; + return Json(result); } - else - { - switch (template.AttachmentType) - { - case AttachmentTypes.Device: - var deviceAssignments = Database.DeviceAttachments - .Include(a => a.Device.AssignedUser) - .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.Device.AssignedUserId != null) - .ToList(); - foreach (var assignment in deviceAssignments) - { - results.Add(new BulkGenerateUserModel() - { - Id = assignment.Device.AssignedUserId, - DisplayName = assignment.Device.AssignedUser.DisplayName, - UserEmailAddress = assignment.Device.AssignedUser.EmailAddress, - Scope = $"Document Template '{template.Id}' Attachment Matches Assigned Device '{assignment.Device.SerialNumber}'", - IsError = false, - }); - } - break; - case AttachmentTypes.Job: - var jobAssignments = Database.JobAttachments - .Include(a => a.Job.User) - .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.Job.UserId != null) - .ToList(); - foreach (var assignment in jobAssignments) - { - results.Add(new BulkGenerateUserModel() - { - Id = assignment.Job.UserId, - DisplayName = assignment.Job.User.DisplayName, - UserEmailAddress = assignment.Job.User.EmailAddress, - Scope = $"Document Template '{template.Id}' Attachment Matches Job '{assignment.Job.Id}'", - IsError = false, - }); - } - break; - case AttachmentTypes.User: - var userAssignments = Database.UserAttachments - .Include(a => a.User) - .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.UserId != null) - .ToList(); - foreach (var assignment in userAssignments) - { - results.Add(new BulkGenerateUserModel() - { - Id = assignment.UserId, - DisplayName = assignment.User.DisplayName, - UserEmailAddress = assignment.User.EmailAddress, - Scope = $"Document Template '{template.Id}' Attachment Matches User", - IsError = false, - }); - } - break; - default: - throw new NotSupportedException(); - } - if (results.Count == 0) - { - if (threshold.HasValue) - { - results.Add(new BulkGenerateUserModel() - { - Id = template.Id, - DisplayName = template.Id, - Scope = $"Document Template has no attachments with associated users after {threshold:yyyy-MM-dd}", - IsError = true, - }); - } - else - { - results.Add(new BulkGenerateUserModel() - { - Id = template.Id, - DisplayName = template.Id, - Scope = $"Document Template has no attachments with associated users", - IsError = true, - }); - } - } - else - { - var distinctSet = new HashSet(StringComparer.Ordinal); - results = results.Where(r => distinctSet.Add(r.Id)).ToList(); - } - } + var results = BulkGenerateEvaluateScope(scope, (template, threshold), BulkGenerateUserAddDocumentTemplateAttachment, BulkGenerateDeviceAddDocumentTemplateAttachment); return Json(results); } + private List BulkGenerateUserAddDocumentTemplateAttachment((DocumentTemplate template, DateTime? threshold) arg) + { + var (template, threshold) = arg; + var results = new List(); - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments, Claims.User.ShowDetails)] + switch (template.AttachmentType) + { + case AttachmentTypes.Device: + var deviceAssignments = Database.DeviceAttachments + .Include(a => a.Device.AssignedUser) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.Device.AssignedUserId != null) + .ToList(); + foreach (var assignment in deviceAssignments) + { + var user = assignment.Device.AssignedUser; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.Device.AssignedUserId, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Document Template '{template.Id}' Attachment Matches Assigned Device '{assignment.Device.SerialNumber}'", + IsError = false, + }); + } + break; + case AttachmentTypes.Job: + var jobAssignments = Database.JobAttachments + .Include(a => a.Job.User) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.Job.UserId != null) + .ToList(); + foreach (var assignment in jobAssignments) + { + var user = assignment.Job.User; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.Job.UserId, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Document Template '{template.Id}' Attachment Matches Job '{assignment.Job.Id}'", + IsError = false, + }); + } + break; + case AttachmentTypes.User: + var userAssignments = Database.UserAttachments + .Include(a => a.User) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.UserId != null) + .ToList(); + foreach (var assignment in userAssignments) + { + var user = assignment.User; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.UserId, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Document Template '{template.Id}' Attachment Matches User", + IsError = false, + }); + } + break; + default: + throw new NotSupportedException(); + } + if (results.Count == 0) + { + if (threshold.HasValue) + { + results.Add(new BulkGenerateItemModel() + { + Id = template.Id, + UserDisplayName = template.Id, + Scope = $"Document Template has no attachments with associated users after {threshold:yyyy-MM-dd}", + IsError = true, + }); + } + else + { + results.Add(new BulkGenerateItemModel() + { + Id = template.Id, + UserDisplayName = template.Id, + Scope = $"Document Template has no attachments with associated users", + IsError = true, + }); + } + } + else + { + var distinctSet = new HashSet(StringComparer.Ordinal); + results = results.Where(r => distinctSet.Add(r.Id)).ToList(); + } + return results; + } + private List BulkGenerateDeviceAddDocumentTemplateAttachment((DocumentTemplate template, DateTime? threshold) arg) + { + var (template, threshold) = arg; + var results = new List(); + + switch (template.AttachmentType) + { + case AttachmentTypes.Device: + var deviceAssignments = Database.DeviceAttachments + .Include(a => a.Device.AssignedUser) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold)) + .ToList(); + foreach (var assignment in deviceAssignments) + { + var user = assignment.Device.AssignedUser; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.DeviceSerialNumber, + UserDisplayName = user?.DisplayName, + UserEmailAddress = user?.EmailAddress, + Scope = $"Document Template '{template.Id}'", + IsError = false, + }); + } + break; + case AttachmentTypes.Job: + var jobAssignments = Database.JobAttachments + .Include(a => a.Job.User) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold) && a.Job.DeviceSerialNumber != null) + .ToList(); + foreach (var assignment in jobAssignments) + { + var user = assignment.Job.User; + if (user != null && UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() + { + Id = assignment.Job.DeviceSerialNumber, + UserDisplayName = user?.DisplayName, + UserEmailAddress = user?.EmailAddress, + Scope = $"Document Template '{template.Id}' Attachment Matches Job '{assignment.Job.Id}'", + IsError = false, + }); + } + break; + case AttachmentTypes.User: + var userAssignments = Database.UserAttachments + .Include(a => a.User.DeviceUserAssignments) + .Where(a => a.DocumentTemplateId == template.Id && (threshold == null || a.Timestamp > threshold)) + .ToList(); + foreach (var assignment in userAssignments) + { + var userDeviceAssignments = assignment.User.CurrentDeviceAssignments; + if (userDeviceAssignments.Any()) + { + var user = assignment.User; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + foreach (var userDeviceAssignment in userDeviceAssignments) + { + results.Add(new BulkGenerateItemModel() + { + Id = userDeviceAssignment.DeviceSerialNumber, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"Document Template '{template.Id}' Attachment Matches User '{user.UserId}'", + IsError = false, + }); + } + } + } + break; + default: + throw new NotSupportedException(); + } + if (results.Count == 0) + { + if (threshold.HasValue) + { + results.Add(new BulkGenerateItemModel() + { + Id = template.Id, + UserDisplayName = template.Id, + Scope = $"Document Template has no attachments after {threshold:yyyy-MM-dd}", + IsError = true, + }); + } + else + { + results.Add(new BulkGenerateItemModel() + { + Id = template.Id, + UserDisplayName = template.Id, + Scope = $"Document Template has no attachments", + IsError = true, + }); + } + } + else + { + var distinctSet = new HashSet(StringComparer.Ordinal); + results = results.Where(r => distinctSet.Add(r.Id)).ToList(); + } + return results; + } + + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] [HttpPost, ValidateAntiForgeryToken] public virtual ActionResult BulkGenerateGetUserDetailValues(string key) { @@ -1262,14 +1644,21 @@ namespace Disco.Web.Areas.API.Controllers return Json(results); } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments, Claims.User.ShowDetails)] + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] [HttpPost, ValidateAntiForgeryToken, ValidateInput(false)] - public virtual ActionResult BulkGenerateAddUserDetail(string key, string value) + public virtual ActionResult BulkGenerateAddUserDetail(string scope, string key, string value) { if (string.IsNullOrWhiteSpace(key)) return BadRequest(); - var results = new List(); + var results = BulkGenerateEvaluateScope(scope, (key, value), BulkGenerateUserAddUserDetail, BulkGenerateDeviceAddUserDetail); + + return Json(results); + } + private List BulkGenerateUserAddUserDetail((string key, string value) arg) + { + var (key, value) = arg; + var results = new List(); var query = Database.UserDetails.Include(d => d.User).Where(d => d.Scope == "Details" && d.Key == key); if (!string.IsNullOrWhiteSpace(value)) @@ -1280,29 +1669,89 @@ namespace Disco.Web.Areas.API.Controllers if (details.Count == 0) { - results.Add(new BulkGenerateUserModel() + results.Add(new BulkGenerateItemModel() { Id = key, - DisplayName = $"{key}{(string.IsNullOrWhiteSpace(value) ? null : $":{value}")}", + UserDisplayName = $"{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()) + foreach (var dbUser in details.Select(d => d.User).Distinct()) { - results.Add(new BulkGenerateUserModel() + var user = dbUser; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + results.Add(new BulkGenerateItemModel() { Id = user.UserId, - DisplayName = user.DisplayName, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, Scope = $"User Detail '{key}'{(string.IsNullOrWhiteSpace(value) ? null : $" with the value '{value}'")} Matches User", IsError = false, }); } } - return Json(results); + return results; + } + private List BulkGenerateDeviceAddUserDetail((string key, string value) arg) + { + var (key, value) = arg; + var results = new List(); + + var query = Database.UserDetails.Include(d => d.User.DeviceUserAssignments).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) + { + foreach (var dbUser in details.Select(d => d.User).Distinct()) + { + var assignments = dbUser.CurrentDeviceAssignments; + if (assignments.Count == 0) + continue; + + var user = dbUser; + if (UserService.TryGetUser(user.UserId, Database, true, out var adUser)) + user = adUser; // use updated user from AD + + foreach (var assignment in assignments) + { + results.Add(new BulkGenerateItemModel() + { + Id = assignment.DeviceSerialNumber, + UserDisplayName = user.DisplayName, + UserEmailAddress = user.EmailAddress, + Scope = $"User Detail '{key}'{(string.IsNullOrWhiteSpace(value) ? null : $" with the value '{value}'")} Matches User '{user.UserId}'", + IsError = false, + }); + } + } + } + if (results.Count == 0) + { + results.Add(new BulkGenerateItemModel() + { + Id = key, + UserDisplayName = $"{key}{(string.IsNullOrWhiteSpace(value) ? null : $":{value}")}", + Scope = $"User Detail '{key}' didn't match any devices{(string.IsNullOrWhiteSpace(value) ? null : $" with the value '{value}'")}", + IsError = true, + }); + } + else + { + var distinctSet = new HashSet(StringComparer.Ordinal); + results = results.Where(r => distinctSet.Add(r.Id)).ToList(); + } + + return results; } [HttpPost, ValidateAntiForgeryToken] diff --git a/Disco.Web/Areas/API/Controllers/UserFlagAssignmentController.cs b/Disco.Web/Areas/API/Controllers/UserFlagAssignmentController.cs index b243bba2..33752070 100644 --- a/Disco.Web/Areas/API/Controllers/UserFlagAssignmentController.cs +++ b/Disco.Web/Areas/API/Controllers/UserFlagAssignmentController.cs @@ -1,6 +1,5 @@ using Disco.Models.Repository; using Disco.Services; -using Disco.Services.Authorization; using Disco.Services.Web; using System; using System.Data.Entity; diff --git a/Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateUserModel.cs b/Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateItemModel.cs similarity index 72% rename from Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateUserModel.cs rename to Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateItemModel.cs index 4cf8776e..4121c5f2 100644 --- a/Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateUserModel.cs +++ b/Disco.Web/Areas/API/Models/DocumentTemplate/BulkGenerateItemModel.cs @@ -1,11 +1,11 @@ namespace Disco.Web.Areas.API.Models.DocumentTemplate { - public class BulkGenerateUserModel + public class BulkGenerateItemModel { public string Id { get; set; } public string UserEmailAddress { get; set; } - public string DisplayName { get; set; } + public string UserDisplayName { get; set; } public string Scope { get; set; } public bool IsError { get; set; } } -} \ No newline at end of file +} diff --git a/Disco.Web/Areas/Config/Controllers/DeviceBatchController.cs b/Disco.Web/Areas/Config/Controllers/DeviceBatchController.cs index 052ef399..77cd9333 100644 --- a/Disco.Web/Areas/Config/Controllers/DeviceBatchController.cs +++ b/Disco.Web/Areas/Config/Controllers/DeviceBatchController.cs @@ -2,7 +2,6 @@ using Disco.Models.UI.Config.DeviceBatch; using Disco.Services; using Disco.Services.Authorization; -using Disco.Services.Devices; using Disco.Services.Devices.ManagedGroups; using Disco.Services.Plugins.Features.UIExtension; using Disco.Services.Web; diff --git a/Disco.Web/Areas/Config/Controllers/DeviceFlagController.cs b/Disco.Web/Areas/Config/Controllers/DeviceFlagController.cs index da77d0a7..b4241b89 100644 --- a/Disco.Web/Areas/Config/Controllers/DeviceFlagController.cs +++ b/Disco.Web/Areas/Config/Controllers/DeviceFlagController.cs @@ -1,5 +1,4 @@ using Disco.Models.Areas.Config.UI.DeviceFlag; -using Disco.Models.Repository; using Disco.Models.Services.Devices.DeviceFlag; using Disco.Models.UI.Config.DeviceFlag; using Disco.Services.Authorization; diff --git a/Disco.Web/Areas/Config/Controllers/DocumentTemplateController.cs b/Disco.Web/Areas/Config/Controllers/DocumentTemplateController.cs index 00158416..2e1a3d39 100644 --- a/Disco.Web/Areas/Config/Controllers/DocumentTemplateController.cs +++ b/Disco.Web/Areas/Config/Controllers/DocumentTemplateController.cs @@ -209,7 +209,7 @@ namespace Disco.Web.Areas.Config.Controllers } else { - ModelState.AddModelError("Id", "A Document Template Package with this Id already exists."); + ModelState.AddModelError(nameof(model.Id), "A Document Template Package with this Id already exists."); } } @@ -219,67 +219,134 @@ namespace Disco.Web.Areas.Config.Controllers return View(model); } - public static ConfigDocumentTemplateBulkGenerate BuildBulkGenerateModel(DocumentTemplate documentTemplate, DiscoDataContext database, AuthorizationToken authorization) + public static (string viewName, ConfigDocumentTemplateBulkGenerate model) BuildBulkGenerateModel(DocumentTemplate documentTemplate, DiscoDataContext database, AuthorizationToken authorization) { - var model = new BulkGenerateModel() - { - DocumentTemplate = documentTemplate, - }; + BulkGenerateModel model; + string viewName; - model.TemplatePageCount = model.DocumentTemplate.PdfPageHasAttachmentId(database).Count; - model.UserFlags = database.UserFlags.Select(f => new ItemWithCount() + if (documentTemplate.Scope == DocumentTemplate.DocumentTemplateScopes.User) { - Item = f, - Count = f.UserFlagAssignments.Where(a => a.RemovedDate == null).Count(), - }).ToList(); - model.DeviceProfiles = database.DeviceProfiles.Select(p => new ItemWithCount() - { - Item = p, - Count = p.Devices.Where(d => d.AssignedUserId != null).Count(), - }).ToList(); - model.DeviceBatches = database.DeviceBatches.Select(p => new ItemWithCount() - { - Item = p, - Count = p.Devices.Where(d => d.AssignedUserId != null).Count(), - }).ToList(); - model.DocumentTemplates = database.DocumentTemplates.Select(dt => new ItemWithCount() - { - Item = dt, - }).ToList(); - foreach (var record in model.DocumentTemplates) - { - switch (record.Item.AttachmentType) + authorization.Require(Claims.User.Actions.GenerateDocuments); + model = new BulkGenerateUserModel() { - case AttachmentTypes.Device: - record.Count = database.DeviceAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Device.AssignedUser).Distinct().Count(); - break; - case AttachmentTypes.Job: - record.Count = database.JobAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Job.User).Distinct().Count(); - break; - case AttachmentTypes.User: - record.Count = database.UserAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.User).Distinct().Count(); - break; - default: - throw new NotSupportedException(); - } - } - if (authorization.Has(Claims.User.ShowDetails)) - { - model.UserDetails = database.UserDetails.Where(d => d.Scope == "Details").GroupBy(d => d.Key).Select(g => new ItemWithCount() + UserFlags = database.UserFlags.Select(f => new ItemWithCount() + { + Item = f, + Count = f.UserFlagAssignments.Where(a => a.RemovedDate == null).Count(), + }).ToList(), + }; + model.DeviceProfiles = database.DeviceProfiles.Select(p => new ItemWithCount() { - Item = g.Key, - Count = g.Count(), + Item = p, + Count = p.Devices.Where(d => d.AssignedUserId != null).Count(), }).ToList(); + model.DeviceBatches = database.DeviceBatches.Select(p => new ItemWithCount() + { + Item = p, + Count = p.Devices.Where(d => d.AssignedUserId != null).Count(), + }).ToList(); + model.DocumentTemplates = database.DocumentTemplates.Select(dt => new ItemWithCount() + { + Item = dt, + }).ToList(); + foreach (var record in model.DocumentTemplates) + { + switch (record.Item.AttachmentType) + { + case AttachmentTypes.Device: + record.Count = database.DeviceAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Device.AssignedUser).Distinct().Count(); + break; + case AttachmentTypes.Job: + record.Count = database.JobAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Job.User).Distinct().Count(); + break; + case AttachmentTypes.User: + record.Count = database.UserAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.User).Distinct().Count(); + break; + default: + throw new NotSupportedException(); + } + } + if (authorization.Has(Claims.User.ShowDetails)) + { + model.UserDetails = database.UserDetails.Where(d => d.Scope == "Details").GroupBy(d => d.Key).Select(g => new ItemWithCount() + { + Item = g.Key, + Count = g.Count(), + }).ToList(); + } + else + { + model.UserDetails = new List>(); + } + viewName = MVC.Config.DocumentTemplate.Views.BulkGenerateUser; + } + else if (documentTemplate.Scope == DocumentTemplate.DocumentTemplateScopes.Device) + { + authorization.Require(Claims.Device.Actions.GenerateDocuments); + model = new BulkGenerateDeviceModel() + { + DeviceFlags = database.DeviceFlags.Select(f => new ItemWithCount() + { + Item = f, + Count = f.DeviceFlagAssignments.Where(a => a.RemovedDate == null).Count(), + }).ToList(), + }; + model.DeviceProfiles = database.DeviceProfiles.Select(p => new ItemWithCount() + { + Item = p, + Count = p.Devices.Count(), + }).ToList(); + model.DeviceBatches = database.DeviceBatches.Select(p => new ItemWithCount() + { + Item = p, + Count = p.Devices.Count(), + }).ToList(); + model.DocumentTemplates = database.DocumentTemplates.Select(dt => new ItemWithCount() + { + Item = dt, + }).ToList(); + foreach (var record in model.DocumentTemplates) + { + switch (record.Item.AttachmentType) + { + case AttachmentTypes.Device: + record.Count = database.DeviceAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Device).Distinct().Count(); + break; + case AttachmentTypes.Job: + record.Count = database.JobAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).Select(a => a.Job.Device).Distinct().Count(); + break; + case AttachmentTypes.User: + record.Count = database.UserAttachments.Where(a => a.DocumentTemplateId == record.Item.Id).SelectMany(a => a.User.DeviceUserAssignments).Where(a => a.UnassignedDate == null).Select(a => a.DeviceSerialNumber).Distinct().Count(); + break; + default: + throw new NotSupportedException(); + } + } + if (authorization.Has(Claims.User.ShowDetails)) + { + model.UserDetails = database.UserDetails.Where(d => d.Scope == "Details").GroupBy(d => d.Key).Select(g => new ItemWithCount() + { + Item = g.Key, + Count = g.Select(i => i.User).SelectMany(u => u.DeviceUserAssignments).Where(a => a.UnassignedDate == null).Count(), + }).ToList(); + } + else + { + model.UserDetails = new List>(); + } + viewName = MVC.Config.DocumentTemplate.Views.BulkGenerateDevice; } else - { - model.UserDetails = new List>(); - } + throw new NotSupportedException("Only user and device scoped document templates can be bulk generated using this method"); - return model; + model.DocumentTemplate = documentTemplate; + + model.TemplatePageCount = model.DocumentTemplate.PdfPageHasAttachmentId(database).Count; + + return (viewName, model); } - [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments)] + [DiscoAuthorizeAll(Claims.Config.DocumentTemplate.BulkGenerate)] public virtual ActionResult BulkGenerate(string id) { var documentTemplate = Database.DocumentTemplates.FirstOrDefault(at => at.Id == id); @@ -287,16 +354,15 @@ namespace Disco.Web.Areas.Config.Controllers if (documentTemplate == null) throw new ArgumentException("Invalid Document Template Id", nameof(id)); - if (documentTemplate.Scope != DocumentTemplate.DocumentTemplateScopes.User) + if (documentTemplate.Scope != DocumentTemplate.DocumentTemplateScopes.User && documentTemplate.Scope != DocumentTemplate.DocumentTemplateScopes.Device) throw new NotSupportedException("Only user-scoped document templates can be bulk generated using this method"); - - var model = BuildBulkGenerateModel(documentTemplate, Database, Authorization); + var (viewName, model) = BuildBulkGenerateModel(documentTemplate, Database, Authorization); // UI Extensions UIExtensions.ExecuteExtensions(ControllerContext, model); - return View(MVC.Config.DocumentTemplate.Views.BulkGenerate, model); + return View(viewName, model); } [HttpGet] diff --git a/Disco.Web/Areas/Config/Controllers/JobQueueController.cs b/Disco.Web/Areas/Config/Controllers/JobQueueController.cs index 07fcbc35..fef72ec7 100644 --- a/Disco.Web/Areas/Config/Controllers/JobQueueController.cs +++ b/Disco.Web/Areas/Config/Controllers/JobQueueController.cs @@ -1,5 +1,4 @@ -using Disco.Models.Repository; -using Disco.Models.Services.Jobs.JobQueues; +using Disco.Models.Services.Jobs.JobQueues; using Disco.Models.UI.Config.JobQueue; using Disco.Services.Authorization; using Disco.Services.Extensions; diff --git a/Disco.Web/Areas/Config/Models/DocumentTemplate/BulkGenerateModel.cs b/Disco.Web/Areas/Config/Models/DocumentTemplate/BulkGenerateModel.cs index 4bb9c223..cb5832c0 100644 --- a/Disco.Web/Areas/Config/Models/DocumentTemplate/BulkGenerateModel.cs +++ b/Disco.Web/Areas/Config/Models/DocumentTemplate/BulkGenerateModel.cs @@ -7,10 +7,19 @@ namespace Disco.Web.Areas.Config.Models.DocumentTemplate { public Disco.Models.Repository.DocumentTemplate DocumentTemplate { get; set; } public int TemplatePageCount { get; set; } - public List> UserFlags { get; set; } public List> DeviceProfiles { get; set; } public List> DeviceBatches { get; set; } public List> DocumentTemplates { get; set; } public List> UserDetails { get; set; } } -} \ No newline at end of file + + public class BulkGenerateUserModel : BulkGenerateModel, ConfigDocumentTemplateBulkGenerateUser + { + public List> UserFlags { get; set; } + } + + public class BulkGenerateDeviceModel : BulkGenerateModel, ConfigDocumentTemplateBulkGenerateDevice + { + public List> DeviceFlags { get; set; } + } +} diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerate.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerate.generated.cs deleted file mode 100644 index 1e410f57..00000000 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/BulkGenerate.generated.cs +++ /dev/null @@ -1,1558 +0,0 @@ -#pragma warning disable 1591 -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Disco.Web.Areas.Config.Views.DocumentTemplate -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Net; - using System.Text; - using System.Web; - using System.Web.Helpers; - using System.Web.Mvc; - using System.Web.Mvc.Ajax; - using System.Web.Mvc.Html; - using System.Web.Routing; - using System.Web.Security; - using System.Web.UI; - using System.Web.WebPages; - using Disco; - using Disco.Models.Repository; - using Disco.Services; - using Disco.Services.Authorization; - - #line 2 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - using Disco.Services.Interop.ActiveDirectory; - - #line default - #line hidden - using Disco.Services.Web; - using Disco.Web; - using Disco.Web.Extensions; - - [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] - [System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/DocumentTemplate/BulkGenerate.cshtml")] - public partial class BulkGenerate : Disco.Services.Web.WebViewPage - { - public BulkGenerate() - { - } - public override void Execute() - { - - #line 3 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - Authorization.RequireAll(Claims.Config.DocumentTemplate.BulkGenerate, Claims.User.Actions.GenerateDocuments); - - ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Document Templates", MVC.Config.DocumentTemplate.Index(null), Model.DocumentTemplate.Description, MVC.Config.DocumentTemplate.Index(Model.DocumentTemplate.Id), "Bulk Generate"); - Html.BundleDeferred("~/ClientScripts/Modules/Disco-DocumentBulkGenerate"); - - - #line default - #line hidden -WriteLiteral("\r\n\r\n \r\n"); - - - #line 11 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 11 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerate(Model.DocumentTemplate.Id))) - { - if (Model.TemplatePageCount > 1 && Model.TemplatePageCount % 2 != 0) - { - - - #line default - #line hidden -WriteLiteral(" "); - -WriteLiteral("Insert Blank Pages for Double-Sided Printing\r\n"); - - - #line 16 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" \r\n"); - -WriteLiteral(" Bulk Generate\r\n"); - - - #line 19 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 19 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - Write(Html.AntiForgeryToken()); - - - #line default - #line hidden - - #line 19 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - } - - - #line default - #line hidden -WriteLiteral("
\r\n Add Users\r\n Add Group Members\r\n"); - - - #line 24 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 24 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - if (Model.UserFlags.Any(f => f.Count > 0)) - { - - - #line default - #line hidden -WriteLiteral(" Add With User Flag\r\n"); - - - #line 27 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" "); - - - #line 28 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - if (Model.DeviceProfiles.Any(b => b.Count > 0)) - { - - - #line default - #line hidden -WriteLiteral(" Add With Device Profile\r\n"); - - - #line 31 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" "); - - - #line 32 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - if (Model.DeviceBatches.Any(b => b.Count > 0)) - { - - - #line default - #line hidden -WriteLiteral(" Add With Device Batch\r\n"); - - - #line 35 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" "); - - - #line 36 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - if (Model.DocumentTemplates.Any(b => b.Count > 0)) - { - - - #line default - #line hidden -WriteLiteral(" Add With Document Attachment\r\n"); - - - #line 39 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" "); - - - #line 40 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - if (Model.UserDetails.Any(b => b.Count > 0)) - { - - - #line default - #line hidden -WriteLiteral(" Add With User Detail\r\n"); - - - #line 43 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - } - - - #line default - #line hidden -WriteLiteral(" \r\n \r\n \r\n \r\n  \r\n " + -" Username\r\n Name\r\n Scop" + -"e\r\n \r\n \r\n \r\n \r\n Add Users\r\n \r\n \r\n \r\n\r\n\r\n(Model.DocumentTemplate.Description - - #line default - #line hidden -, 2908), false) -, Tuple.Create(Tuple.Create("", 2945), Tuple.Create(":", 2945), true) -, Tuple.Create(Tuple.Create(" ", 2946), Tuple.Create("Add", 2947), true) -, Tuple.Create(Tuple.Create(" ", 2950), Tuple.Create("Users", 2951), true) -); - -WriteLiteral(">\r\n \r\n
\r\n Enter multiple User Ids separated by <new line>, commas (,) or semicolons (;). -
-
- Security Groups can also be included. Members will be resolved and added. -
- \r\n

Examples:

\r\n \r\n user6
\r\n smi0099
\r\n"); - -WriteLiteral(" "); - - - #line 75 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName); - - - #line default - #line hidden -WriteLiteral("\\rsmith
\r\n Domain Admins\r\n \r\n user6,smi0099,"); - - - #line 78 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName); - - - #line default - #line hidden -WriteLiteral("\\rsmith,Domain Admins\r\n user6;smi0099;"); - - - #line 79 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName); - - - #line default - #line hidden -WriteLiteral("\\rsmith;Domain Admins\r\n \r\n \r\n"); - - - #line 82 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 82 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerateAddUsers())) - { - - - #line default - #line hidden -WriteLiteral(" \r\n"); - -WriteLiteral(" \r\n"); - - - #line 86 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 86 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - Write(Html.AntiForgeryToken()); - - - #line default - #line hidden - - #line 86 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - } - - - #line default - #line hidden -WriteLiteral("\r\n\r\n(Model.DocumentTemplate.Description - - #line default - #line hidden -, 4411), false) -, Tuple.Create(Tuple.Create("", 4448), Tuple.Create(":", 4448), true) -, Tuple.Create(Tuple.Create(" ", 4449), Tuple.Create("Add", 4450), true) -, Tuple.Create(Tuple.Create(" ", 4453), Tuple.Create("Group", 4454), true) -, Tuple.Create(Tuple.Create(" ", 4459), Tuple.Create("Members", 4460), true) -); - -WriteLiteral(">\r\n \r\n
\r\n Add all members of a group (including recursive mem" + -"bers) to the bulk generation.\r\n
\r\n \r\n"); - - - #line 96 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - - - #line default - #line hidden - - #line 96 "..\..\Areas\Config\Views\DocumentTemplate\BulkGenerate.cshtml" - using (Html.BeginForm(MVC.API.DocumentTemplate.BulkGenerateAddGroupMembers())) - { - - - #line default - #line hidden -WriteLiteral(" \r\n \r\n \r\n \r\n " + -" Group:\r\n \r\n \r\n " + -"