diff --git a/Disco.BI/BI/Extensions/DeviceDetailExtensions.cs b/Disco.BI/BI/Extensions/DeviceDetailExtensions.cs index 3e7e45bc..36bba661 100644 --- a/Disco.BI/BI/Extensions/DeviceDetailExtensions.cs +++ b/Disco.BI/BI/Extensions/DeviceDetailExtensions.cs @@ -66,7 +66,7 @@ namespace Disco.BI.Extensions detail.Value = Value; } } - } + } #endregion #region LanMacAddress @@ -84,7 +84,7 @@ namespace Disco.BI.Extensions public static void LanMacAddress(this IEnumerable details, Device device, string LanMacAddress) { device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyLanMacAddress, LanMacAddress); - } + } #endregion #region WLanMacAddress @@ -102,7 +102,7 @@ namespace Disco.BI.Extensions public static void WLanMacAddress(this IEnumerable details, Device device, string WLanMacAddress) { device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyWLanMacAddress, WLanMacAddress); - } + } #endregion #region ACAdapter @@ -123,5 +123,22 @@ namespace Disco.BI.Extensions } #endregion + #region Battery + /// + /// Gets the Battery Device Detail Value + /// + /// The Battery or null + public static string Battery(this IEnumerable details) + { + return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyBattery); + } + /// + /// Sets the Battery Device Detail Value + /// + public static void Battery(this IEnumerable details, Device device, string Battery) + { + device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyBattery, Battery); + } + #endregion } } diff --git a/Disco.Models/Repository/Device/DeviceDetail.cs b/Disco.Models/Repository/Device/DeviceDetail.cs index 0053598f..c17296dc 100644 --- a/Disco.Models/Repository/Device/DeviceDetail.cs +++ b/Disco.Models/Repository/Device/DeviceDetail.cs @@ -14,6 +14,7 @@ namespace Disco.Models.Repository public const string HardwareKeyLanMacAddress = "LanMacAddress"; public const string HardwareKeyWLanMacAddress = "WLanMacAddress"; public const string HardwareKeyACAdapter = "ACAdapter"; + public const string HardwareKeyBattery = "Battery"; [Column(Order = 0), Key] public string DeviceSerialNumber { get; set; } diff --git a/Disco.Models/Services/Devices/Exporting/DeviceExportOptions.cs b/Disco.Models/Services/Devices/Exporting/DeviceExportOptions.cs index db701596..f3b1eea5 100644 --- a/Disco.Models/Services/Devices/Exporting/DeviceExportOptions.cs +++ b/Disco.Models/Services/Devices/Exporting/DeviceExportOptions.cs @@ -11,6 +11,11 @@ namespace Disco.Models.Services.Devices.Exporting { public DeviceExportTypes ExportType { get; set; } public int? ExportTypeTargetId { get; set; } + + /// + /// Adds '=' to the beginning of the string to stop Excel removing the leading zeros + /// + public bool ExcelCsvFormat { get; set; } // Device [Display(ShortName = "Device", Name = "Serial Number", Description = "The device serial number")] @@ -41,6 +46,8 @@ namespace Disco.Models.Services.Devices.Exporting public bool DetailWLanMacAddress { get; set; } [Display(ShortName = "Details", Name = "AC Adapter", Description = "The AC Adapter associated with the device")] public bool DetailACAdapter { get; set; } + [Display(ShortName = "Details", Name = "Battery", Description = "The Battery associated with the device")] + public bool DetailBattery { get; set; } // Model [Display(ShortName = "Model", Name = "Identifier", Description = "The identifier of the device model associated with the device")] @@ -124,6 +131,7 @@ namespace Disco.Models.Services.Devices.Exporting return new DeviceExportOptions() { ExportType = DeviceExportTypes.All, + ExcelCsvFormat = true, DeviceSerialNumber = true, ModelId = true, ProfileId = true, diff --git a/Disco.Models/Services/Devices/Importing/DeviceImportFieldTypes.cs b/Disco.Models/Services/Devices/Importing/DeviceImportFieldTypes.cs index 92972246..d3e26d40 100644 --- a/Disco.Models/Services/Devices/Importing/DeviceImportFieldTypes.cs +++ b/Disco.Models/Services/Devices/Importing/DeviceImportFieldTypes.cs @@ -26,6 +26,8 @@ namespace Disco.Models.Services.Devices.Importing DetailWLanMacAddress, [Display(Name = "Device AC Adapter", Description = "The AC Adapter associated with the device")] DetailACAdapter, + [Display(Name = "Device Battery", Description = "The Battery associated with the device")] + DetailBattery, [Display(Name = "Model Identifier", Description = "The identifier of the device model associated with the device")] ModelId, diff --git a/Disco.Services/Devices/Exporting/DeviceExport.cs b/Disco.Services/Devices/Exporting/DeviceExport.cs index 89d29076..b2ea5afc 100644 --- a/Disco.Services/Devices/Exporting/DeviceExport.cs +++ b/Disco.Services/Devices/Exporting/DeviceExport.cs @@ -39,7 +39,7 @@ namespace Disco.Services.Devices.Exporting { UserService.GetUser(userId, Database); } - catch (Exception) {} // Ignore Errors + catch (Exception) { } // Ignore Errors }); } @@ -74,9 +74,19 @@ namespace Disco.Services.Devices.Exporting foreach (var record in records) { writer.WriteLine(); - writer.Write(string.Join(",", metadata.Select(m => { + writer.Write(string.Join(",", metadata.Select(m => + { var value = m.Item3(record); - return (m.Item4 && value != null) ? string.Concat("\"", value, "\"") : value; + var isString = m.Item4; + + if (value == null) + return null; + else if (!isString) + return value; + else if (Options.ExcelCsvFormat) + return string.Concat("=\"", value, "\""); + else + return string.Concat("\"", value, "\""); }))); } } @@ -116,12 +126,17 @@ namespace Disco.Services.Devices.Exporting private static IEnumerable BuildRecords(IQueryable Devices) { - var deviceDetailHardwareKeys = new List { DeviceDetail.HardwareKeyLanMacAddress, DeviceDetail.HardwareKeyWLanMacAddress, DeviceDetail.HardwareKeyACAdapter }; + var deviceDetailHardwareKeys = new List { + DeviceDetail.HardwareKeyLanMacAddress, + DeviceDetail.HardwareKeyWLanMacAddress, + DeviceDetail.HardwareKeyACAdapter, + DeviceDetail.HardwareKeyBattery + }; return Devices.Select(d => new DeviceExportRecord() { Device = d, - + DeviceDetails = d.DeviceDetails.Where(dd => dd.Scope == DeviceDetail.ScopeHardware && deviceDetailHardwareKeys.Contains(dd.Key)), ModelId = d.DeviceModelId, @@ -165,7 +180,8 @@ namespace Disco.Services.Devices.Exporting .Where(p => p.PropertyType == typeof(bool)) .Select(p => Tuple.Create(p, (DisplayAttribute)p.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault())) .Where(p => p.Item2 != null && (bool)p.Item1.GetValue(Options)) - .Select(p => { + .Select(p => + { var accessor = allAssessors.First(i => i.Item1 == p.Item1.Name); var columnName = (p.Item2.ShortName == "Device" || p.Item2.ShortName == "Details") ? p.Item2.Name : string.Format("{0} {1}", p.Item2.ShortName, p.Item2.Name); return Tuple.Create(p.Item1.Name, columnName, accessor.Item2, accessor.Item3); @@ -188,12 +204,13 @@ namespace Disco.Services.Devices.Exporting yield return new Tuple, bool>("DeviceFirstEnrolledDate", r => r.Device.EnrolledDate.HasValue ? r.Device.EnrolledDate.Value.ToString(DateTimeFormat) : null, false); yield return new Tuple, bool>("DeviceLastEnrolledDate", r => r.Device.LastEnrolDate.HasValue ? r.Device.LastEnrolDate.Value.ToString(DateTimeFormat) : null, false); yield return new Tuple, bool>("DeviceDecommissionedDate", r => r.Device.DecommissionedDate.HasValue ? r.Device.DecommissionedDate.Value.ToString(DateTimeFormat) : null, false); - yield return new Tuple, bool>("DeviceDecommissionedReason", r => r.Device.DecommissionReason.HasValue ? r.Device.DecommissionReason.Value.ToString() : null, true); + yield return new Tuple, bool>("DeviceDecommissionedReason", r => r.Device.DecommissionReason.HasValue ? r.Device.DecommissionReason.Value.ToString() : null, true); // Details yield return new Tuple, bool>("DetailLanMacAddress", r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyLanMacAddress).Select(dd => dd.Value).FirstOrDefault(), true); yield return new Tuple, bool>("DetailWLanMacAddress", r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyWLanMacAddress).Select(dd => dd.Value).FirstOrDefault(), true); yield return new Tuple, bool>("DetailACAdapter", r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyACAdapter).Select(dd => dd.Value).FirstOrDefault(), true); + yield return new Tuple, bool>("DetailBattery", r => r.DeviceDetails.Where(dd => dd.Key == DeviceDetail.HardwareKeyBattery).Select(dd => dd.Value).FirstOrDefault(), true); // Model yield return new Tuple, bool>("ModelId", r => r.ModelId.HasValue ? r.ModelId.Value.ToString() : null, false); diff --git a/Disco.Services/Devices/Importing/DeviceImport.cs b/Disco.Services/Devices/Importing/DeviceImport.cs index f69b02de..2d1cccda 100644 --- a/Disco.Services/Devices/Importing/DeviceImport.cs +++ b/Disco.Services/Devices/Importing/DeviceImport.cs @@ -30,6 +30,7 @@ namespace Disco.Services.Devices.Importing { DeviceImportFieldTypes.DetailLanMacAddress, typeof(DetailLanMacAddressImportField) }, { DeviceImportFieldTypes.DetailWLanMacAddress, typeof(DetailWLanMacAddressImportField) }, { DeviceImportFieldTypes.DetailACAdapter, typeof(DetailACAdapterImportField) }, + { DeviceImportFieldTypes.DetailBattery, typeof(DetailBatteryImportField) }, { DeviceImportFieldTypes.ModelId, typeof(ModelIdImportField) }, diff --git a/Disco.Services/Devices/Importing/Fields/AssignedUserIdImportField.cs b/Disco.Services/Devices/Importing/Fields/AssignedUserIdImportField.cs index f526f022..fd355641 100644 --- a/Disco.Services/Devices/Importing/Fields/AssignedUserIdImportField.cs +++ b/Disco.Services/Devices/Importing/Fields/AssignedUserIdImportField.cs @@ -5,7 +5,6 @@ using Disco.Services.Users; using System; using System.Collections.Generic; using System.Data; -using System.Globalization; using System.Linq; namespace Disco.Services.Devices.Importing.Fields diff --git a/Disco.Services/Devices/Importing/Fields/DetailBatteryImportField.cs b/Disco.Services/Devices/Importing/Fields/DetailBatteryImportField.cs new file mode 100644 index 00000000..373a6d15 --- /dev/null +++ b/Disco.Services/Devices/Importing/Fields/DetailBatteryImportField.cs @@ -0,0 +1,98 @@ +using Disco.Data.Repository; +using Disco.Models.Repository; +using Disco.Models.Services.Devices.Importing; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; + +namespace Disco.Services.Devices.Importing.Fields +{ + internal class DetailBatteryImportField : DeviceImportFieldBase + { + private string parsedValue; + private string previousValue; + + public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DetailBattery; } } + + public override object RawParsedValue { get { return parsedValue; } } + public override string FriendlyValue { get { return parsedValue; } } + public override string FriendlyPreviousValue { get { return previousValue; } } + + public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary Values, string Value) + { + if (string.IsNullOrWhiteSpace(Value)) + parsedValue = null; + else + { + parsedValue = Value.Trim(); + } + + if (ExistingDevice == null && parsedValue != null) + return Success(EntityState.Added); + else if (ExistingDevice != null) + { + var detail = ExistingDevice.DeviceDetails.FirstOrDefault(dd => dd.Scope == DeviceDetail.ScopeHardware && dd.Key == DeviceDetail.HardwareKeyBattery); + + if (detail == null && parsedValue == null) + return Success(EntityState.Unchanged); + else if (detail == null && parsedValue != null) + { + return Success(EntityState.Modified); + } + else if (detail.Value != parsedValue) + { + previousValue = detail.Value; + return Success(EntityState.Modified); + } + else + return Success(EntityState.Unchanged); + } + else + return Success(EntityState.Unchanged); + } + + public override bool Apply(DiscoDataContext Database, Device Device) + { + if (this.FieldAction == EntityState.Added || + this.FieldAction == EntityState.Modified) + { + + DeviceDetail detail = Database.DeviceDetails.FirstOrDefault(dd => + dd.DeviceSerialNumber == Device.SerialNumber && + dd.Scope == DeviceDetail.ScopeHardware && + dd.Key == DeviceDetail.HardwareKeyBattery); + + if (detail == null) + { + detail = new DeviceDetail() + { + Device = Device, + DeviceSerialNumber = Device.SerialNumber, + Scope = DeviceDetail.ScopeHardware, + Key = DeviceDetail.HardwareKeyBattery + }; + Database.DeviceDetails.Add(detail); + } + + detail.Value = parsedValue; + return true; + } + else + { + return false; + } + } + + public override int? GuessHeader(DiscoDataContext Database, DeviceImportContext Context) + { + // column name + var possibleColumns = Context.Header + .Select((h, i) => Tuple.Create(h, i)) + .Where(h => h.Item1.Item2 == DeviceImportFieldTypes.IgnoreColumn && + h.Item1.Item1.IndexOf("battery", System.StringComparison.OrdinalIgnoreCase) >= 0); + + return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault(); + } + } +} diff --git a/Disco.Services/Devices/Importing/Fields/DeviceDecommissionedReasonImportField.cs b/Disco.Services/Devices/Importing/Fields/DeviceDecommissionedReasonImportField.cs index 84c1eda3..44b9c6e0 100644 --- a/Disco.Services/Devices/Importing/Fields/DeviceDecommissionedReasonImportField.cs +++ b/Disco.Services/Devices/Importing/Fields/DeviceDecommissionedReasonImportField.cs @@ -4,9 +4,7 @@ using Disco.Models.Services.Devices.Importing; using System; using System.Collections.Generic; using System.Data; -using System.Globalization; using System.Linq; -using System.Text; namespace Disco.Services.Devices.Importing.Fields { diff --git a/Disco.Services/Disco.Services.csproj b/Disco.Services/Disco.Services.csproj index 0f76a6e2..cf4fa595 100644 --- a/Disco.Services/Disco.Services.csproj +++ b/Disco.Services/Disco.Services.csproj @@ -188,6 +188,7 @@ + @@ -326,7 +327,7 @@ - + diff --git a/Disco.Web/Areas/API/Controllers/DeviceController.cs b/Disco.Web/Areas/API/Controllers/DeviceController.cs index 64d62a4f..1afe51d6 100644 --- a/Disco.Web/Areas/API/Controllers/DeviceController.cs +++ b/Disco.Web/Areas/API/Controllers/DeviceController.cs @@ -27,6 +27,7 @@ namespace Disco.Web.Areas.API.Controllers const string pLocation = "location"; const string pAllowUnauthenticatedEnrol = "allowunauthenticatedenrol"; const string pDetailACAdapter = "detailacadapter"; + const string pDetailBattery = "detailbattery"; public virtual ActionResult Update(string id, string key, string value = null, bool redirect = false) { @@ -71,6 +72,10 @@ namespace Disco.Web.Areas.API.Controllers Authorization.Require(Claims.Device.Properties.Details); UpdateDetailACAdapter(device, value); break; + case pDetailBattery: + Authorization.Require(Claims.Device.Properties.Details); + UpdateDetailBattery(device, value); + break; default: throw new Exception("Invalid Update Key"); } @@ -145,6 +150,12 @@ namespace Disco.Web.Areas.API.Controllers return Update(id, pDetailACAdapter, DetailACAdapter, redirect); } + [DiscoAuthorize(Claims.Device.Properties.Details)] + public virtual ActionResult UpdateDetailBattery(string id, string DetailBattery = null, bool redirect = false) + { + return Update(id, pDetailBattery, DetailBattery, redirect); + } + #endregion #region Update Properties @@ -258,6 +269,14 @@ namespace Disco.Web.Areas.API.Controllers device.DeviceDetails.ACAdapter(device, ACAdapter.Trim()); Database.SaveChanges(); } + private void UpdateDetailBattery(Disco.Models.Repository.Device device, string Battery) + { + if (string.IsNullOrWhiteSpace(Battery)) + device.DeviceDetails.Battery(device, null); + else + device.DeviceDetails.Battery(device, Battery.Trim()); + Database.SaveChanges(); + } #endregion #region Device Actions diff --git a/Disco.Web/T4MVC.cs b/Disco.Web/T4MVC.cs index 0d83dcc6..9d4374eb 100644 --- a/Disco.Web/T4MVC.cs +++ b/Disco.Web/T4MVC.cs @@ -3543,6 +3543,12 @@ namespace Disco.Web.Areas.API.Controllers } [NonAction] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public virtual System.Web.Mvc.ActionResult UpdateDetailBattery() + { + return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateDetailBattery); + } + [NonAction] + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public virtual System.Web.Mvc.ActionResult Decommission() { return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Decommission); @@ -3661,6 +3667,7 @@ namespace Disco.Web.Areas.API.Controllers public readonly string UpdateAssignedUserId = "UpdateAssignedUserId"; public readonly string UpdateAllowUnauthenticatedEnrol = "UpdateAllowUnauthenticatedEnrol"; public readonly string UpdateDetailACAdapter = "UpdateDetailACAdapter"; + public readonly string UpdateDetailBattery = "UpdateDetailBattery"; public readonly string Decommission = "Decommission"; public readonly string Recommission = "Recommission"; public readonly string Delete = "Delete"; @@ -3691,6 +3698,7 @@ namespace Disco.Web.Areas.API.Controllers public const string UpdateAssignedUserId = "UpdateAssignedUserId"; public const string UpdateAllowUnauthenticatedEnrol = "UpdateAllowUnauthenticatedEnrol"; public const string UpdateDetailACAdapter = "UpdateDetailACAdapter"; + public const string UpdateDetailBattery = "UpdateDetailBattery"; public const string Decommission = "Decommission"; public const string Recommission = "Recommission"; public const string Delete = "Delete"; @@ -3793,6 +3801,16 @@ namespace Disco.Web.Areas.API.Controllers public readonly string DetailACAdapter = "DetailACAdapter"; public readonly string redirect = "redirect"; } + static readonly ActionParamsClass_UpdateDetailBattery s_params_UpdateDetailBattery = new ActionParamsClass_UpdateDetailBattery(); + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public ActionParamsClass_UpdateDetailBattery UpdateDetailBatteryParams { get { return s_params_UpdateDetailBattery; } } + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public class ActionParamsClass_UpdateDetailBattery + { + public readonly string id = "id"; + public readonly string DetailBattery = "DetailBattery"; + public readonly string redirect = "redirect"; + } static readonly ActionParamsClass_Decommission s_params_Decommission = new ActionParamsClass_Decommission(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public ActionParamsClass_Decommission DecommissionParams { get { return s_params_Decommission; } } @@ -4046,6 +4064,18 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } + partial void UpdateDetailBatteryOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string DetailBattery, bool redirect); + + public override System.Web.Mvc.ActionResult UpdateDetailBattery(string id, string DetailBattery, bool redirect) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateDetailBattery); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DetailBattery", DetailBattery); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect); + UpdateDetailBatteryOverride(callInfo, id, DetailBattery, redirect); + return callInfo; + } + partial void DecommissionOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, int Reason, bool redirect); public override System.Web.Mvc.ActionResult Decommission(string id, int Reason, bool redirect) diff --git a/Disco.Web/Views/Device/DeviceParts/_Details.cshtml b/Disco.Web/Views/Device/DeviceParts/_Details.cshtml index 97f61ee2..949f40fc 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Details.cshtml +++ b/Disco.Web/Views/Device/DeviceParts/_Details.cshtml @@ -38,6 +38,23 @@ } + + Battery + @if (canConfig) + { + @Html.TextBox("DeviceDetail_Battery", Model.Device.DeviceDetails.Battery()) @AjaxHelpers.AjaxSave() @AjaxHelpers.AjaxLoader() + + } + else + { + @(Model.Device.DeviceDetails.Battery() ?? "Unknown") + } + + diff --git a/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs index 45c2f03d..5d87a325 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34011 +// Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -188,6 +188,95 @@ WriteLiteral("\', \'DetailACAdapter\');\r\n });\r\n } + #line default + #line hidden +WriteLiteral(" \r\n \r\n \r\n " + +" Battery\r\n "); + + + #line 43 "..\..\Views\Device\DeviceParts\_Details.cshtml" + if (canConfig) + { + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + Write(Html.TextBox("DeviceDetail_Battery", Model.Device.DeviceDetails.Battery())); + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + Write(AjaxHelpers.AjaxSave()); + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + Write(AjaxHelpers.AjaxLoader()); + + + #line default + #line hidden + + #line 45 "..\..\Views\Device\DeviceParts\_Details.cshtml" + + + + #line default + #line hidden +WriteLiteral("