feature: export device custom details

This commit is contained in:
Gary Sharp
2022-12-04 12:05:54 +11:00
parent ed58619919
commit dff47c0e8b
3 changed files with 59 additions and 15 deletions
@@ -88,6 +88,8 @@ namespace Disco.Models.Services.Devices.Exporting
public bool AssignedUserPhoneNumber { get; set; } public bool AssignedUserPhoneNumber { get; set; }
[Display(ShortName = "Assigned User", Name = "Email Address", Description = "The email address of the user assigned to the device")] [Display(ShortName = "Assigned User", Name = "Email Address", Description = "The email address of the user assigned to the device")]
public bool AssignedUserEmailAddress { get; set; } public bool AssignedUserEmailAddress { get; set; }
[Display(ShortName = "Assigned User", Name = "Custom Details", Description = "The custom details provided by plugins for the user assigned to the device")]
public bool AssignedUserDetailCustom { get; set; }
// Jobs // Jobs
[Display(ShortName = "Jobs", Name = "Count", Description = "The total number of jobs associated with the device")] [Display(ShortName = "Jobs", Name = "Count", Description = "The total number of jobs associated with the device")]
@@ -128,6 +130,8 @@ namespace Disco.Models.Services.Devices.Exporting
public bool DetailBattery { get; set; } public bool DetailBattery { get; set; }
[Display(ShortName = "Details", Name = "Keyboard", Description = "The Keyboard associated with the device")] [Display(ShortName = "Details", Name = "Keyboard", Description = "The Keyboard associated with the device")]
public bool DetailKeyboard { get; set; } public bool DetailKeyboard { get; set; }
[Display(ShortName = "Details", Name = "Custom Details", Description = "Custom details provided by plugins")]
public bool DetailCustom { get; set; }
public static DeviceExportOptions DefaultOptions() public static DeviceExportOptions DefaultOptions()
{ {
@@ -21,6 +21,7 @@ namespace Disco.Models.Services.Devices.Exporting
public List<string> DeviceDetailLanMacAddresses { get; set; } public List<string> DeviceDetailLanMacAddresses { get; set; }
public List<string> DeviceDetailWlanMacAddresses { get; set; } public List<string> DeviceDetailWlanMacAddresses { get; set; }
public List<Battery> DeviceDetailBatteries { get; set; } public List<Battery> DeviceDetailBatteries { get; set; }
public Dictionary<string, string> DeviceDetailCustom { get; set; }
// Model // Model
public int? ModelId { get; set; } public int? ModelId { get; set; }
@@ -48,6 +49,8 @@ namespace Disco.Models.Services.Devices.Exporting
// User // User
public DeviceUserAssignment DeviceUserAssignment { get; set; } public DeviceUserAssignment DeviceUserAssignment { get; set; }
public User AssignedUser { get; set; } public User AssignedUser { get; set; }
public IList<UserDetail> AssignedUserDetails { get; set; }
public Dictionary<string, string> AssignedUserCustomDetails { get; set; }
// Jobs // Jobs
public int JobsTotalCount { get; set; } public int JobsTotalCount { get; set; }
@@ -2,12 +2,14 @@
using Disco.Data.Repository; using Disco.Data.Repository;
using Disco.Models.Repository; using Disco.Models.Repository;
using Disco.Models.Services.Devices.Exporting; using Disco.Models.Services.Devices.Exporting;
using Disco.Services.Plugins.Features.DetailsProvider;
using Disco.Services.Tasks; using Disco.Services.Tasks;
using Disco.Services.Users; using Disco.Services.Users;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.Data; using System.Data;
using System.Data.Entity;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -17,12 +19,18 @@ namespace Disco.Services.Devices.Exporting
public static class DeviceExport public static class DeviceExport
{ {
public static DeviceExportResult GenerateExport(DiscoDataContext Database, IQueryable<Device> Devices, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus) public static DeviceExportResult GenerateExport(DiscoDataContext Database, Func<IQueryable<Device>, IQueryable<Device>> Filter, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus)
{ {
TaskStatus.UpdateStatus(15, "Extracting records from the database"); TaskStatus.UpdateStatus(15, "Extracting records from the database");
var records = BuildRecords(Devices).ToList(); var devices = Database.Devices
.Include(d => d.AssignedUser.UserDetails)
.Include(d => d.DeviceDetails);
if (Filter != null)
devices = Filter(devices);
var records = BuildRecords(devices).ToList();
// materialize device details // materialize device details
records.ForEach(r => records.ForEach(r =>
{ {
@@ -49,6 +57,12 @@ namespace Disco.Services.Devices.Exporting
} }
if (Options.DetailBatteries) if (Options.DetailBatteries)
r.DeviceDetailBatteries = r.DeviceDetails.Batteries(); r.DeviceDetailBatteries = r.DeviceDetails.Batteries();
var detailsService = new DetailsProviderService(Database);
if (Options.DetailCustom)
r.DeviceDetailCustom = detailsService.GetDetails(r.Device).Details;
if (Options.AssignedUserDetailCustom && r.AssignedUser != null)
r.AssignedUserCustomDetails = detailsService.GetDetails(r.AssignedUser).Details;
}); });
TaskStatus.UpdateStatus(40, "Building metadata and database query"); TaskStatus.UpdateStatus(40, "Building metadata and database query");
@@ -65,7 +79,7 @@ namespace Disco.Services.Devices.Exporting
Options.AssignedUserEmailAddress) Options.AssignedUserEmailAddress)
{ {
TaskStatus.UpdateStatus(45, "Updating Assigned User details"); TaskStatus.UpdateStatus(45, "Updating Assigned User details");
var users = Devices.Where(d => d.AssignedUserId != null).Select(d => d.AssignedUser).Distinct().ToList(); var users = records.Where(d => d.AssignedUser != null).Select(d => d.AssignedUser).Distinct().ToList();
users.Select((user, index) => users.Select((user, index) =>
{ {
@@ -119,26 +133,21 @@ namespace Disco.Services.Devices.Exporting
}; };
} }
public static DeviceExportResult GenerateExport(DiscoDataContext Database, IQueryable<Device> Devices, DeviceExportOptions Options)
{
return GenerateExport(Database, Devices, Options, ScheduledTaskMockStatus.Create("Device Export"));
}
public static DeviceExportResult GenerateExport(DiscoDataContext Database, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus) public static DeviceExportResult GenerateExport(DiscoDataContext Database, DeviceExportOptions Options, IScheduledTaskStatus TaskStatus)
{ {
switch (Options.ExportType) switch (Options.ExportType)
{ {
case DeviceExportTypes.All: case DeviceExportTypes.All:
return GenerateExport(Database, Database.Devices, Options, TaskStatus); return GenerateExport(Database, null, Options, TaskStatus);
case DeviceExportTypes.Batch: case DeviceExportTypes.Batch:
if (Options.ExportTypeTargetId.HasValue && Options.ExportTypeTargetId.Value > 0) if (Options.ExportTypeTargetId.HasValue && Options.ExportTypeTargetId.Value > 0)
return GenerateExport(Database, Database.Devices.Where(d => d.DeviceBatchId == Options.ExportTypeTargetId), Options, TaskStatus); return GenerateExport(Database, devices => devices.Where(d => d.DeviceBatchId == Options.ExportTypeTargetId), Options, TaskStatus);
else else
return GenerateExport(Database, Database.Devices.Where(d => d.DeviceBatchId == null), Options, TaskStatus); return GenerateExport(Database, devices => devices.Where(d => d.DeviceBatchId == null), Options, TaskStatus);
case DeviceExportTypes.Model: case DeviceExportTypes.Model:
return GenerateExport(Database, Database.Devices.Where(d => d.DeviceModelId == Options.ExportTypeTargetId), Options, TaskStatus); return GenerateExport(Database, devices => devices.Where(d => d.DeviceModelId == Options.ExportTypeTargetId), Options, TaskStatus);
case DeviceExportTypes.Profile: case DeviceExportTypes.Profile:
return GenerateExport(Database, Database.Devices.Where(d => d.DeviceProfileId == Options.ExportTypeTargetId), Options, TaskStatus); return GenerateExport(Database, devices => devices.Where(d => d.DeviceProfileId == Options.ExportTypeTargetId), Options, TaskStatus);
default: default:
throw new ArgumentException(string.Format("Unknown Device Export Type", Options.ExportType.ToString()), "Options"); throw new ArgumentException(string.Format("Unknown Device Export Type", Options.ExportType.ToString()), "Options");
} }
@@ -229,6 +238,7 @@ namespace Disco.Services.Devices.Exporting
DeviceUserAssignment = d.DeviceUserAssignments.Where(dua => dua.UnassignedDate == null).FirstOrDefault(), DeviceUserAssignment = d.DeviceUserAssignments.Where(dua => dua.UnassignedDate == null).FirstOrDefault(),
AssignedUser = d.AssignedUser, AssignedUser = d.AssignedUser,
AssignedUserDetails = d.AssignedUser.UserDetails,
JobsTotalCount = d.Jobs.Count(), JobsTotalCount = d.Jobs.Count(),
JobsOpenCount = d.Jobs.Count(j => j.ClosedDate == null), JobsOpenCount = d.Jobs.Count(j => j.ClosedDate == null),
@@ -249,7 +259,14 @@ namespace Disco.Services.Devices.Exporting
var certificateMaxCount = Math.Max(1, records.Max(r => r.DeviceCertificates?.Count() ?? 0)); var certificateMaxCount = Math.Max(1, records.Max(r => r.DeviceCertificates?.Count() ?? 0));
var batteriesMaxCount = Math.Max(1, records.Max(r => r.DeviceDetailBatteries?.Count ?? 0)); var batteriesMaxCount = Math.Max(1, records.Max(r => r.DeviceDetailBatteries?.Count ?? 0));
var allAssessors = BuildRecordAccessors(processorMaxCount, memoryMaxCount, diskDriveMaxCount, lanAdapterMaxCount, wlanAdapterMaxCount, certificateMaxCount, batteriesMaxCount); IEnumerable<string> deviceDetailCustomKeys = null;
IEnumerable<string> assignedUserDetailCustomKeys = null;
if (options.DetailCustom)
deviceDetailCustomKeys = records.Where(r => r.DeviceDetailCustom != null).SelectMany(r => r.DeviceDetailCustom.Keys).Distinct(StringComparer.OrdinalIgnoreCase).ToList();
if (options.AssignedUserDetailCustom)
assignedUserDetailCustomKeys = records.Where(r => r.AssignedUserCustomDetails != null).SelectMany(r => r.AssignedUserCustomDetails.Keys).Distinct(StringComparer.OrdinalIgnoreCase).ToList();
var allAssessors = BuildRecordAccessors(processorMaxCount, memoryMaxCount, diskDriveMaxCount, lanAdapterMaxCount, wlanAdapterMaxCount, certificateMaxCount, batteriesMaxCount, deviceDetailCustomKeys, assignedUserDetailCustomKeys);
return typeof(DeviceExportOptions).GetProperties() return typeof(DeviceExportOptions).GetProperties()
.Where(p => p.PropertyType == typeof(bool)) .Where(p => p.PropertyType == typeof(bool))
@@ -271,7 +288,7 @@ namespace Disco.Services.Devices.Exporting
}).ToList(); }).ToList();
} }
private static Dictionary<string, List<DeviceExportFieldMetadata>> BuildRecordAccessors(int processorMaxCount, int memoryMaxCount, int diskDriveMaxCount, int lanAdapterMaxCount, int wlanAdapterMaxCount, int certificateMaxCount, int batteriesMaxCount) private static Dictionary<string, List<DeviceExportFieldMetadata>> BuildRecordAccessors(int processorMaxCount, int memoryMaxCount, int diskDriveMaxCount, int lanAdapterMaxCount, int wlanAdapterMaxCount, int certificateMaxCount, int batteriesMaxCount, IEnumerable<string> deviceDetailCustomKeys, IEnumerable<string> assignedUserDetailCustomKeys)
{ {
const string DateFormat = "yyyy-MM-dd"; const string DateFormat = "yyyy-MM-dd";
const string DateTimeFormat = DateFormat + " HH:mm:ss"; const string DateTimeFormat = DateFormat + " HH:mm:ss";
@@ -330,6 +347,16 @@ namespace Disco.Services.Devices.Exporting
metadata.Add(nameof(DeviceExportOptions.AssignedUserGivenName), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserGivenName), typeof(string), r => r.AssignedUser?.GivenName, csvStringEncoded) }); metadata.Add(nameof(DeviceExportOptions.AssignedUserGivenName), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserGivenName), typeof(string), r => r.AssignedUser?.GivenName, csvStringEncoded) });
metadata.Add(nameof(DeviceExportOptions.AssignedUserPhoneNumber), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserPhoneNumber), typeof(string), r => r.AssignedUser?.PhoneNumber, csvStringEncoded) }); metadata.Add(nameof(DeviceExportOptions.AssignedUserPhoneNumber), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserPhoneNumber), typeof(string), r => r.AssignedUser?.PhoneNumber, csvStringEncoded) });
metadata.Add(nameof(DeviceExportOptions.AssignedUserEmailAddress), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserEmailAddress), typeof(string), r => r.AssignedUser?.EmailAddress, csvStringEncoded) }); metadata.Add(nameof(DeviceExportOptions.AssignedUserEmailAddress), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.AssignedUserEmailAddress), typeof(string), r => r.AssignedUser?.EmailAddress, csvStringEncoded) });
if (assignedUserDetailCustomKeys != null)
{
var assignedUserDetailCustomFields = new List<DeviceExportFieldMetadata>();
foreach (var detailKey in assignedUserDetailCustomKeys.OrderBy(k => k, StringComparer.OrdinalIgnoreCase))
{
var key = detailKey;
assignedUserDetailCustomFields.Add(new DeviceExportFieldMetadata(detailKey, detailKey, typeof(string), r => r.AssignedUserCustomDetails != null && r.AssignedUserCustomDetails.TryGetValue(key, out var value) ? value : null, csvStringEncoded));
}
metadata.Add(nameof(DeviceExportOptions.AssignedUserDetailCustom), assignedUserDetailCustomFields);
}
// Jobs // Jobs
metadata.Add(nameof(DeviceExportOptions.JobsTotalCount), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.JobsTotalCount), typeof(int), r => r.JobsTotalCount, csvToStringEncoded) }); metadata.Add(nameof(DeviceExportOptions.JobsTotalCount), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.JobsTotalCount), typeof(int), r => r.JobsTotalCount, csvToStringEncoded) });
@@ -508,6 +535,16 @@ namespace Disco.Services.Devices.Exporting
} }
metadata.Add(nameof(DeviceExportOptions.DetailBatteries), batteriesFields); metadata.Add(nameof(DeviceExportOptions.DetailBatteries), batteriesFields);
metadata.Add(nameof(DeviceExportOptions.DetailKeyboard), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.DetailKeyboard), typeof(string), r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyKeyboard).Select(dd => dd.Value).FirstOrDefault(), csvStringEncoded) }); metadata.Add(nameof(DeviceExportOptions.DetailKeyboard), new List<DeviceExportFieldMetadata>() { new DeviceExportFieldMetadata(nameof(DeviceExportOptions.DetailKeyboard), typeof(string), r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyKeyboard).Select(dd => dd.Value).FirstOrDefault(), csvStringEncoded) });
if (deviceDetailCustomKeys != null)
{
var deviceDetailCustomFields = new List<DeviceExportFieldMetadata>();
foreach (var detailKey in deviceDetailCustomKeys.OrderBy(k => k, StringComparer.OrdinalIgnoreCase))
{
var key = detailKey;
deviceDetailCustomFields.Add(new DeviceExportFieldMetadata(detailKey, detailKey, typeof(string), r => r.DeviceDetailCustom != null && r.DeviceDetailCustom.TryGetValue(key, out var value) ? value : null, csvStringEncoded));
}
metadata.Add(nameof(DeviceExportOptions.DetailCustom), deviceDetailCustomFields);
}
return metadata; return metadata;
} }