Feature #33: Enhanced Device Importing
Dynamic device importing. better input parsing and 5 additional import fields.
This commit is contained in:
@@ -1,272 +0,0 @@
|
|||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
|
||||||
using Disco.Services.Users;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using PopulateRecordReferences = System.Tuple<System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceModel>, System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceProfile>, System.Collections.Generic.Dictionary<int, Disco.Models.Repository.DeviceBatch>>;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public static class Import
|
|
||||||
{
|
|
||||||
internal const string ImportParseCacheKey = "ImportParseResults_{0}";
|
|
||||||
|
|
||||||
public static ImportDeviceSession GetSession(string ImportParseTaskId)
|
|
||||||
{
|
|
||||||
string parseKey = string.Format(ImportParseCacheKey, ImportParseTaskId);
|
|
||||||
|
|
||||||
return (ImportDeviceSession)HttpRuntime.Cache.Get(parseKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static bool ImportRecord(this ImportDevice device, DiscoDataContext Database, PopulateRecordReferences references)
|
|
||||||
{
|
|
||||||
// Skips If Errors
|
|
||||||
if (device.Errors == null || device.Errors.Count == 0)
|
|
||||||
{
|
|
||||||
// Re-Populate & Skip If Errors
|
|
||||||
device.PopulateRecord(Database, references);
|
|
||||||
if (device.Errors == null || device.Errors.Count == 0)
|
|
||||||
{
|
|
||||||
Device discoDevice = device.Device;
|
|
||||||
|
|
||||||
if (discoDevice == null)
|
|
||||||
{
|
|
||||||
// New Device
|
|
||||||
discoDevice = new Device()
|
|
||||||
{
|
|
||||||
SerialNumber = device.SerialNumber.ToUpper(),
|
|
||||||
CreatedDate = DateTime.Now,
|
|
||||||
AllowUnauthenticatedEnrol = true,
|
|
||||||
};
|
|
||||||
Database.Devices.Add(discoDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (discoDevice.DeviceModelId != device.DeviceModelId)
|
|
||||||
discoDevice.DeviceModelId = device.DeviceModelId;
|
|
||||||
if (discoDevice.DeviceProfileId != device.DeviceProfileId)
|
|
||||||
discoDevice.DeviceProfileId = device.DeviceProfileId;
|
|
||||||
if (discoDevice.DeviceBatchId != device.DeviceBatchId)
|
|
||||||
discoDevice.DeviceBatchId = device.DeviceBatchId;
|
|
||||||
if (discoDevice.Location != device.Location)
|
|
||||||
discoDevice.Location = device.Location;
|
|
||||||
if (discoDevice.AssetNumber != device.AssetNumber)
|
|
||||||
discoDevice.AssetNumber = device.AssetNumber;
|
|
||||||
|
|
||||||
if (discoDevice.AssignedUserId != device.AssignedUserId)
|
|
||||||
{
|
|
||||||
discoDevice.AssignDevice(Database, device.AssignedUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
Database.SaveChanges();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static PopulateRecordReferences GetPopulateRecordReferences(DiscoDataContext Database)
|
|
||||||
{
|
|
||||||
return new PopulateRecordReferences(
|
|
||||||
Database.DeviceModels.ToDictionary(dm => dm.Id),
|
|
||||||
Database.DeviceProfiles.ToDictionary(dp => dp.Id),
|
|
||||||
Database.DeviceBatches.ToDictionary(db => db.Id)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void PopulateRecord(this ImportDevice device, DiscoDataContext Database, PopulateRecordReferences references)
|
|
||||||
{
|
|
||||||
|
|
||||||
var deviceModels = references.Item1;
|
|
||||||
var deviceProfiles = references.Item2;
|
|
||||||
var deviceBatches = references.Item3;
|
|
||||||
|
|
||||||
// SERIAL NUMBER - Existing Device
|
|
||||||
if (!device.Errors.ContainsKey("SerialNumber"))
|
|
||||||
{
|
|
||||||
device.Device = Database.Devices.Find(device.SerialNumber);
|
|
||||||
if (device.Device != null && device.Device.DecommissionedDate.HasValue)
|
|
||||||
device.Errors.Add("SerialNumber", "The device is decommissioned");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// DEVICE MODEL
|
|
||||||
if (!device.Errors.ContainsKey("DeviceModelId"))
|
|
||||||
{
|
|
||||||
DeviceModel deviceModel;
|
|
||||||
|
|
||||||
if (!device.DeviceModelId.HasValue)
|
|
||||||
device.DeviceModelId = 1; // Default 'Unknown Device Model'
|
|
||||||
|
|
||||||
if (!deviceModels.TryGetValue(device.DeviceModelId.Value, out deviceModel))
|
|
||||||
device.Errors.Add("DeviceModelId", string.Format("Unknown device model id: {0}", device.DeviceModelId));
|
|
||||||
else
|
|
||||||
device.DeviceModel = deviceModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVICE PROFILE
|
|
||||||
if (!device.Errors.ContainsKey("DeviceProfileId"))
|
|
||||||
{
|
|
||||||
DeviceProfile deviceProfile;
|
|
||||||
if (!deviceProfiles.TryGetValue(device.DeviceProfileId, out deviceProfile))
|
|
||||||
device.Errors.Add("DeviceProfileId", string.Format("Unknown device profile id: {0}", device.DeviceProfileId));
|
|
||||||
else
|
|
||||||
device.DeviceProfile = deviceProfile;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DEVICE BATCH
|
|
||||||
if (!device.Errors.ContainsKey("DeviceBatchId") && device.DeviceBatchId.HasValue)
|
|
||||||
{
|
|
||||||
DeviceBatch deviceBatch;
|
|
||||||
if (!deviceBatches.TryGetValue(device.DeviceBatchId.Value, out deviceBatch))
|
|
||||||
device.Errors.Add("DeviceBatchId", string.Format("Unknown device Batch id: {0}", device.DeviceBatchId));
|
|
||||||
else
|
|
||||||
device.DeviceBatch = deviceBatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ASSIGNED USER
|
|
||||||
if (!device.Errors.ContainsKey("AssignedUserId") && device.AssignedUserId != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
device.AssignedUser = UserService.GetUser(device.AssignedUserId, Database, true);
|
|
||||||
}
|
|
||||||
catch (ArgumentException)
|
|
||||||
{
|
|
||||||
device.Errors.Add("AssignedUserId", string.Format("Unknown user id: {0}", device.AssignedUserId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static ImportDevice ParseRecord(this string[] record)
|
|
||||||
{
|
|
||||||
int csvFieldCount = record.Length;
|
|
||||||
if (csvFieldCount < 1)
|
|
||||||
throw new ArgumentException("At least one CSV field is required (Serial Number)");
|
|
||||||
|
|
||||||
string csvSerialNumber;
|
|
||||||
string csvDeviceModelId;
|
|
||||||
int deviceModelId = 1; // Default 'Unknown Device Model'
|
|
||||||
string csvDeviceProfileId;
|
|
||||||
int deviceProfileId = 1; // 'Default' Profile
|
|
||||||
string csvDeviceBatchId;
|
|
||||||
int deviceBatchId = 0; // No Batch
|
|
||||||
string csvAssignedUserId = null;
|
|
||||||
string csvLocation = null;
|
|
||||||
string csvAssetNumber = null;
|
|
||||||
Dictionary<string, string> errors = new Dictionary<string, string>();
|
|
||||||
|
|
||||||
// SERIAL NUMBER
|
|
||||||
csvSerialNumber = record[0];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvSerialNumber))
|
|
||||||
errors.Add("SerialNumber", "The serial number is required");
|
|
||||||
else if (csvSerialNumber.Trim().Length > 60)
|
|
||||||
errors.Add("SerialNumber", "The serial number must be less than or equal to 60 characters");
|
|
||||||
|
|
||||||
if (csvFieldCount > 1)
|
|
||||||
{
|
|
||||||
// DEVICE MODEL
|
|
||||||
csvDeviceModelId = record[1];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceModelId))
|
|
||||||
if (!int.TryParse(csvDeviceModelId, out deviceModelId))
|
|
||||||
errors.Add("DeviceModelId", "The device model is optional, but when supplied must be a number");
|
|
||||||
else if (deviceModelId < 1)
|
|
||||||
errors.Add("DeviceModelId", "The device model is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 2)
|
|
||||||
{
|
|
||||||
// DEVICE PROFILE
|
|
||||||
csvDeviceProfileId = record[2];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceProfileId))
|
|
||||||
if (!int.TryParse(csvDeviceProfileId, out deviceProfileId))
|
|
||||||
errors.Add("DeviceProfileId", "The device profile is optional, but when supplied must be a number");
|
|
||||||
else if (deviceProfileId < 1)
|
|
||||||
errors.Add("DeviceProfileId", "The device profile is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 3)
|
|
||||||
{
|
|
||||||
// DEVICE BATCH
|
|
||||||
csvDeviceBatchId = record[3];
|
|
||||||
if (!string.IsNullOrWhiteSpace(csvDeviceBatchId))
|
|
||||||
if (!int.TryParse(csvDeviceBatchId, out deviceBatchId))
|
|
||||||
errors.Add("DeviceBatchId", "The device batch is optional, but when supplied must be a number");
|
|
||||||
else if (deviceBatchId < 1)
|
|
||||||
errors.Add("DeviceBatchId", "The device batch is optional, but when supplied must be greater than 0");
|
|
||||||
|
|
||||||
if (csvFieldCount > 4)
|
|
||||||
{
|
|
||||||
// ASSIGNED USER
|
|
||||||
csvAssignedUserId = record[4];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvAssignedUserId))
|
|
||||||
csvAssignedUserId = null; // Not Assigned
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (csvAssignedUserId.Length > 50)
|
|
||||||
errors.Add("AssignedUserId", "The assigned user must be less than or equal to 50 characters");
|
|
||||||
else if (!csvAssignedUserId.Contains('\\')) // Assume Primary Domain
|
|
||||||
csvAssignedUserId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, csvAssignedUserId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (csvFieldCount > 5)
|
|
||||||
{
|
|
||||||
// LOCATION
|
|
||||||
csvLocation = record[5];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvLocation))
|
|
||||||
csvLocation = null; // No Location Specified
|
|
||||||
else if (csvLocation.Length > 250)
|
|
||||||
errors.Add("Location", "The location must be less than or equal to 250 characters");
|
|
||||||
|
|
||||||
if (csvFieldCount > 6)
|
|
||||||
{
|
|
||||||
// ASSET NUMBER
|
|
||||||
csvAssetNumber = record[6];
|
|
||||||
if (string.IsNullOrWhiteSpace(csvAssetNumber))
|
|
||||||
csvAssetNumber = null; // No Location Specified
|
|
||||||
else if (csvAssetNumber.Length > 40)
|
|
||||||
errors.Add("AssetNumber", "The asset number must be less than or equal to 40 characters");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ImportDevice()
|
|
||||||
{
|
|
||||||
SerialNumber = csvSerialNumber.Trim(),
|
|
||||||
DeviceModelId = deviceModelId,
|
|
||||||
DeviceProfileId = deviceProfileId,
|
|
||||||
DeviceBatchId = deviceBatchId == 0 ? (int?)null : deviceBatchId,
|
|
||||||
AssignedUserId = csvAssignedUserId,
|
|
||||||
Location = csvLocation,
|
|
||||||
AssetNumber = csvAssetNumber,
|
|
||||||
Errors = errors
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#region ImportDevice Extensions
|
|
||||||
|
|
||||||
public static string ImportStatus(this ImportDevice device)
|
|
||||||
{
|
|
||||||
if (device.Errors.Count > 0)
|
|
||||||
return "Error";
|
|
||||||
|
|
||||||
if (device.Device != null)
|
|
||||||
return "Update";
|
|
||||||
|
|
||||||
return "New";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using LumenWorks.Framework.IO.Csv;
|
|
||||||
using Quartz;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using System.Web.Caching;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public class ImportParseTask : ScheduledTask
|
|
||||||
{
|
|
||||||
public override string TaskName { get { return "Import Devices - Parsing"; } }
|
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return false; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
string csvFilename = (string)this.ExecutionContext.JobDetail.JobDataMap["CsvFilename"];
|
|
||||||
MemoryStream csvStream = (MemoryStream)this.ExecutionContext.JobDetail.JobDataMap["CsvImport"];
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(0, "Parsing CSV File", "Loading Records");
|
|
||||||
|
|
||||||
List<ImportDevice> records;
|
|
||||||
|
|
||||||
using (TextReader csvTextReader = new StreamReader(csvStream))
|
|
||||||
{
|
|
||||||
using (CsvReader csvReader = new CsvReader(csvTextReader, true))
|
|
||||||
{
|
|
||||||
csvReader.DefaultParseErrorAction = ParseErrorAction.ThrowException;
|
|
||||||
csvReader.MissingFieldAction = MissingFieldAction.ReplaceByNull;
|
|
||||||
|
|
||||||
records = csvReader.Select(record => record.ParseRecord()).ToList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
csvStream.Dispose();
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(20, "Parsing CSV File", string.Format("Linking {0} Records", records.Count));
|
|
||||||
|
|
||||||
using (DiscoDataContext database = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
var populateReferences = Import.GetPopulateRecordReferences(database);
|
|
||||||
|
|
||||||
DateTime lastUpdate = DateTime.Now;
|
|
||||||
foreach (var record in records)
|
|
||||||
{
|
|
||||||
record.PopulateRecord(database, populateReferences);
|
|
||||||
|
|
||||||
if (DateTime.Now.Subtract(lastUpdate).TotalSeconds > 1)
|
|
||||||
{
|
|
||||||
// Update every second
|
|
||||||
this.Status.UpdateStatus((int)Math.Floor((((double)(records.IndexOf(record) + 1) / records.Count) * 80)));
|
|
||||||
lastUpdate = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Session Result
|
|
||||||
ImportDeviceSession session = new ImportDeviceSession()
|
|
||||||
{
|
|
||||||
ImportParseTaskId = this.Status.SessionId,
|
|
||||||
ImportFilename = csvFilename,
|
|
||||||
ImportDevices = records
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set Results to Cache
|
|
||||||
string key = string.Format(Import.ImportParseCacheKey, this.Status.SessionId);
|
|
||||||
HttpRuntime.Cache.Insert(key, session, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(60), CacheItemPriority.NotRemovable, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScheduledTaskStatus Run(Stream CsvImport, String CsvFilename)
|
|
||||||
{
|
|
||||||
|
|
||||||
MemoryStream csvStream = new MemoryStream();
|
|
||||||
CsvImport.CopyTo(csvStream);
|
|
||||||
csvStream.Position = 0;
|
|
||||||
|
|
||||||
var task = new ImportParseTask();
|
|
||||||
JobDataMap taskData = new JobDataMap() { { "CsvImport", csvStream }, { "CsvFilename", CsvFilename } };
|
|
||||||
return task.ScheduleTask(taskData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.BI.Device;
|
|
||||||
using Disco.Services.Tasks;
|
|
||||||
using Quartz;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Disco.BI.DeviceBI.Importing
|
|
||||||
{
|
|
||||||
public class ImportProcessTask : ScheduledTask
|
|
||||||
{
|
|
||||||
public override string TaskName { get { return "Import Devices - Processing Changes"; } }
|
|
||||||
|
|
||||||
public override bool SingleInstanceTask { get { return false; } }
|
|
||||||
public override bool CancelInitiallySupported { get { return false; } }
|
|
||||||
|
|
||||||
protected override void ExecuteTask()
|
|
||||||
{
|
|
||||||
string importParseTaskId = (string)this.ExecutionContext.JobDetail.JobDataMap["ImportParseTaskId"];
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(importParseTaskId))
|
|
||||||
throw new ArgumentNullException("ImportParseTaskId");
|
|
||||||
|
|
||||||
ImportDeviceSession session = Import.GetSession(importParseTaskId);
|
|
||||||
|
|
||||||
if (session == null)
|
|
||||||
throw new InvalidOperationException("The session timed out (60 minutes), try importing again");
|
|
||||||
|
|
||||||
List<ImportDevice> records = session.ImportDevices;
|
|
||||||
int recordsImported = 0;
|
|
||||||
|
|
||||||
this.Status.UpdateStatus(0, "Processing Device Import", "Importing Devices");
|
|
||||||
|
|
||||||
using (DiscoDataContext database = new DiscoDataContext())
|
|
||||||
{
|
|
||||||
var populateReferences = Import.GetPopulateRecordReferences(database);
|
|
||||||
|
|
||||||
DateTime lastUpdate = DateTime.Now;
|
|
||||||
foreach (var record in records)
|
|
||||||
{
|
|
||||||
if (record.ImportRecord(database, populateReferences))
|
|
||||||
recordsImported++;
|
|
||||||
|
|
||||||
if (DateTime.Now.Subtract(lastUpdate).TotalSeconds > 1)
|
|
||||||
{
|
|
||||||
// Update every second
|
|
||||||
this.Status.UpdateStatus((int)Math.Floor((((double)(records.IndexOf(record) + 1) / records.Count) * 100)), string.Format("Importing: {0} ({1} of {2})", record.SerialNumber, records.IndexOf(record) + 1, records.Count));
|
|
||||||
lastUpdate = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.Status.SetFinishedMessage(string.Format("Imported {0} of {1} Devices", recordsImported, records.Count));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScheduledTaskStatus Run(string ImportParseTaskId)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(ImportParseTaskId))
|
|
||||||
throw new ArgumentNullException("ImportParseTaskId");
|
|
||||||
|
|
||||||
var task = new ImportProcessTask();
|
|
||||||
JobDataMap taskData = new JobDataMap() { { "ImportParseTaskId", ImportParseTaskId } };
|
|
||||||
return task.ScheduleTask(taskData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
using Disco.BI.Wireless.eduSTAR;
|
|
||||||
using Disco.Data.Configuration;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.BI.Extensions;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Threading;
|
|
||||||
namespace Disco.BI.Wireless
|
|
||||||
{
|
|
||||||
public abstract class BaseWirelessProvider
|
|
||||||
{
|
|
||||||
protected DiscoDataContext dbContext;
|
|
||||||
private static object _CertificateAllocateLock = System.Runtime.CompilerServices.RuntimeHelpers.GetObjectValue(new object());
|
|
||||||
public static BaseWirelessProvider GetProvider(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
string provider = dbContext.DiscoConfiguration.Wireless.Provider;
|
|
||||||
if (provider == "eduSTAR")
|
|
||||||
{
|
|
||||||
return new eduSTARWirelessProvider(dbContext);
|
|
||||||
}
|
|
||||||
throw new System.NotSupportedException(string.Format("Wireless Provider Not Supported: '{0}'", dbContext.DiscoConfiguration.Wireless.Provider));
|
|
||||||
}
|
|
||||||
protected BaseWirelessProvider(DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
this.dbContext = dbContext;
|
|
||||||
}
|
|
||||||
private DeviceCertificate CertificateAllocate(ref Device repoDevice)
|
|
||||||
{
|
|
||||||
lock (BaseWirelessProvider._CertificateAllocateLock)
|
|
||||||
{
|
|
||||||
this.FillCertificateAutoBuffer();
|
|
||||||
int timeout = 60;
|
|
||||||
int freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
while (!(freeCertCount > 0 | timeout <= 0))
|
|
||||||
{
|
|
||||||
System.Threading.Thread.Sleep(500);
|
|
||||||
freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
timeout--;
|
|
||||||
}
|
|
||||||
DeviceCertificate cert = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).FirstOrDefault();
|
|
||||||
if (cert == null)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogAllocationFailed(repoDevice.SerialNumber);
|
|
||||||
throw new System.InvalidOperationException("Unable to Allocate a Wireless Certificate");
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogAllocated(cert.Name, repoDevice.SerialNumber);
|
|
||||||
cert.DeviceSerialNumber = repoDevice.SerialNumber;
|
|
||||||
cert.AllocatedDate = System.DateTime.Now;
|
|
||||||
this.dbContext.SaveChanges();
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public DeviceCertificate Enrol(Device repoDevice)
|
|
||||||
{
|
|
||||||
DeviceCertificate allocatedCert = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == repoDevice.SerialNumber && c.Enabled).FirstOrDefault();
|
|
||||||
if (allocatedCert != null)
|
|
||||||
{
|
|
||||||
return allocatedCert;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
|
||||||
//if (repoDevice.DeviceProfile.Configuration(this.dbContext).AllocateWirelessCertificate)
|
|
||||||
if (repoDevice.DeviceProfile.AllocateCertificate)
|
|
||||||
{
|
|
||||||
allocatedCert = this.CertificateAllocate(ref repoDevice);
|
|
||||||
return allocatedCert;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected abstract void FillCertificateAutoBuffer();
|
|
||||||
public abstract void FillCertificateBuffer(int Amount);
|
|
||||||
public abstract System.Collections.Generic.List<string> RemoveExistingCertificateNames();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,304 +0,0 @@
|
|||||||
using Disco.Logging;
|
|
||||||
using Disco.Logging.Models;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
namespace Disco.BI.Wireless
|
|
||||||
{
|
|
||||||
public class WirelessCertificatesLog : LogBase
|
|
||||||
{
|
|
||||||
public enum EventTypeIds
|
|
||||||
{
|
|
||||||
RetrievalStarting = 10,
|
|
||||||
RetrievalProgress,
|
|
||||||
RetrievalFinished,
|
|
||||||
RetrievalWarning = 15,
|
|
||||||
RetrievalError,
|
|
||||||
RetrievalCertificateStarting = 20,
|
|
||||||
RetrievalCertificateFinished = 22,
|
|
||||||
RetrievalCertificateWarning = 25,
|
|
||||||
RetrievalCertificateError,
|
|
||||||
Allocated = 40,
|
|
||||||
AllocationFailed = 50
|
|
||||||
}
|
|
||||||
private const int _ModuleId = 60;
|
|
||||||
private static bool _IsCertificateRetrievalProcessing;
|
|
||||||
private static string _CertificateRetrievalStatus;
|
|
||||||
private static int _CertificateRetrievalProgress;
|
|
||||||
public static WirelessCertificatesLog Current
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return (WirelessCertificatesLog)LogContext.LogModules[60];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public static bool IsCertificateRetrievalProcessing
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return WirelessCertificatesLog._IsCertificateRetrievalProcessing;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleDescription
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "Wireless Certificates";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override int ModuleId
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return 60;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override string ModuleName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return "WirelessCertificates";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
[System.Diagnostics.DebuggerNonUserCode]
|
|
||||||
public WirelessCertificatesLog()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
private static void Log(WirelessCertificatesLog.EventTypeIds EventTypeId, params object[] Args)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Current.Log((int)EventTypeId, Args);
|
|
||||||
}
|
|
||||||
public static void LogRetrievalStarting(int CertificateCount, int CertificateIdFrom, int CertificateIdTo)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalStarting, new object[]
|
|
||||||
{
|
|
||||||
CertificateCount,
|
|
||||||
CertificateIdFrom,
|
|
||||||
CertificateIdTo
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalFinished()
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalFinished, new object[0]);
|
|
||||||
}
|
|
||||||
public static void LogRetrievalWarning(string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalWarning, new object[]
|
|
||||||
{
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalError(string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalError, new object[]
|
|
||||||
{
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateStarting(string CertificateId)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateStarting, new object[]
|
|
||||||
{
|
|
||||||
CertificateId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateFinished(string CertificateId)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateFinished, new object[]
|
|
||||||
{
|
|
||||||
CertificateId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateWarning(string CertificateId, string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateWarning, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogRetrievalCertificateError(string CertificateId, string Message)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalCertificateError, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
Message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogAllocated(string CertificateId, string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.Allocated, new object[]
|
|
||||||
{
|
|
||||||
CertificateId,
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogAllocationFailed(string DeviceSerialNumber)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.AllocationFailed, new object[]
|
|
||||||
{
|
|
||||||
DeviceSerialNumber
|
|
||||||
});
|
|
||||||
}
|
|
||||||
public static void LogCertificateRetrievalProgress(bool? IsProcessing, int? Progress, string Status)
|
|
||||||
{
|
|
||||||
bool flag = IsProcessing.HasValue;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._IsCertificateRetrievalProcessing = IsProcessing.Value;
|
|
||||||
}
|
|
||||||
flag = WirelessCertificatesLog._IsCertificateRetrievalProcessing;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
bool flag2 = Status != null;
|
|
||||||
if (flag2)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus = Status;
|
|
||||||
}
|
|
||||||
flag2 = Progress.HasValue;
|
|
||||||
if (flag2)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress = Progress.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus = null;
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress = 0;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.Log(WirelessCertificatesLog.EventTypeIds.RetrievalProgress, new object[]
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog._IsCertificateRetrievalProcessing,
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalProgress,
|
|
||||||
WirelessCertificatesLog._CertificateRetrievalStatus
|
|
||||||
});
|
|
||||||
}
|
|
||||||
protected override System.Collections.Generic.List<LogEventType> LoadEventTypes()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<LogEventType>
|
|
||||||
{
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 10,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Starting",
|
|
||||||
Format = "Starting retrieval of {0} certificate/s ({1} to {2})",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 11,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Progress",
|
|
||||||
Format = "Processing: {0}; {1}% Complete; Status: {2}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = false,
|
|
||||||
UseDisplay = false
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 12,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Finished",
|
|
||||||
Format = "Retrieval of Certificates Complete",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 15,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Warning",
|
|
||||||
Format = "Retrieval Warning: {0}",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 16,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Error",
|
|
||||||
Format = "Retrieval Error: {0}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 20,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Starting",
|
|
||||||
Format = "Retrieving Certificate: {0}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 22,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Finished",
|
|
||||||
Format = "Certificate Retrieved: {0}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 25,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Warning",
|
|
||||||
Format = "{0} Certificate Warning: {1}",
|
|
||||||
Severity = 1,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 26,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Retrieval Certificate Error",
|
|
||||||
Format = "{0} Certificate Error: {1}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 40,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Allocated",
|
|
||||||
Format = "Certificate {0} allocated to {1}",
|
|
||||||
Severity = 0,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
},
|
|
||||||
new LogEventType
|
|
||||||
{
|
|
||||||
Id = 50,
|
|
||||||
ModuleId = 60,
|
|
||||||
Name = "Allocation Failed",
|
|
||||||
Format = "No certificates available for Device: {0}",
|
|
||||||
Severity = 2,
|
|
||||||
UseLive = true,
|
|
||||||
UsePersist = true,
|
|
||||||
UseDisplay = true
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
using Disco.BI.Wireless.eduSTAR.eduSTARWirelessCertService;
|
|
||||||
using Disco.Data.Repository;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Ionic.Zip;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Linq.Expressions;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
using System.ServiceModel;
|
|
||||||
using System.ServiceModel.Channels;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace Disco.BI.Wireless.eduSTAR
|
|
||||||
{
|
|
||||||
public class eduSTARWirelessProvider : BaseWirelessProvider
|
|
||||||
{
|
|
||||||
private class BulkLoadCertificatesContract
|
|
||||||
{
|
|
||||||
public int Start { get; set; }
|
|
||||||
public int Count { get; set; }
|
|
||||||
}
|
|
||||||
private static object _BulkLoadThreadLock = new object();
|
|
||||||
private static System.Threading.Thread _BulkLoadThread;
|
|
||||||
public eduSTARWirelessProvider(DiscoDataContext dbContext)
|
|
||||||
: base(dbContext)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
protected override void FillCertificateAutoBuffer()
|
|
||||||
{
|
|
||||||
int freeCertCount = this.dbContext.DeviceCertificates.Where(c => c.DeviceSerialNumber == null && c.Enabled).Count();
|
|
||||||
if (freeCertCount <= this.dbContext.DiscoConfiguration.Wireless.CertificateAutoBufferLow)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificates(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public override void FillCertificateBuffer(int Amount)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificates(Amount);
|
|
||||||
}
|
|
||||||
public override System.Collections.Generic.List<string> RemoveExistingCertificateNames()
|
|
||||||
{
|
|
||||||
return new System.Collections.Generic.List<string>
|
|
||||||
{
|
|
||||||
"(eduPaSS)",
|
|
||||||
"(CN=Computers, ?DC=services, ?DC=education, ?DC=vic, ?DC=gov, ?DC=au)"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
private void BulkLoadCertificates(int Amount = 0)
|
|
||||||
{
|
|
||||||
if (eduSTARWirelessProvider._BulkLoadThread == null)
|
|
||||||
{
|
|
||||||
lock (eduSTARWirelessProvider._BulkLoadThreadLock)
|
|
||||||
{
|
|
||||||
if (eduSTARWirelessProvider._BulkLoadThread == null)
|
|
||||||
{
|
|
||||||
int start = 0;
|
|
||||||
if (this.dbContext.DeviceCertificates.Count() > 0)
|
|
||||||
{
|
|
||||||
start = this.dbContext.DeviceCertificates.Max(c => c.ProviderIndex) + 1;
|
|
||||||
}
|
|
||||||
int buffer = this.dbContext.DeviceCertificates.Count(c => c.DeviceSerialNumber == null && c.Enabled);
|
|
||||||
int count = this.dbContext.DiscoConfiguration.Wireless.CertificateAutoBufferMax - buffer;
|
|
||||||
if (Amount > 0)
|
|
||||||
{
|
|
||||||
count = Amount;
|
|
||||||
}
|
|
||||||
if (count > 0)
|
|
||||||
{
|
|
||||||
eduSTARWirelessProvider.BulkLoadCertificatesContract contract = new eduSTARWirelessProvider.BulkLoadCertificatesContract
|
|
||||||
{
|
|
||||||
Start = start,
|
|
||||||
Count = count
|
|
||||||
};
|
|
||||||
System.Threading.ParameterizedThreadStart threadStart = delegate(object a0)
|
|
||||||
{
|
|
||||||
this.BulkLoadCertificatesStart((eduSTARWirelessProvider.BulkLoadCertificatesContract)a0);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread = new System.Threading.Thread(threadStart);
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread.Start(contract);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private void BulkLoadCertificatesStart(eduSTARWirelessProvider.BulkLoadCertificatesContract contract)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalStarting(contract.Count, contract.Start, contract.Start + contract.Count - 1);
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(true, 0, string.Format("Starting Bulk Retrieval (Loading {0} Certificate/s)", contract.Count));
|
|
||||||
DiscoDataContext dbLocalContext = new DiscoDataContext();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertServiceSoapClient proxy = this.GetProxy();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int num = contract.Start + contract.Count - 1;
|
|
||||||
int index = contract.Start;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
int num2 = num;
|
|
||||||
if (index > num2)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(true, (int)System.Math.Round(unchecked(((double)checked(index - contract.Start) + 0.5) / (double)contract.Count * 100.0)), string.Format("Retrieving Certificate {0} of {1}", index - contract.Start + 1, contract.Count));
|
|
||||||
DeviceCertificate cert = this.LoadCertificate(index, proxy, dbLocalContext);
|
|
||||||
dbLocalContext.DeviceCertificates.Add(cert);
|
|
||||||
dbLocalContext.SaveChanges();
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateFinished(cert.Name);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = proxy != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)proxy).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = dbLocalContext != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)dbLocalContext).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalError(string.Format("[{0}] {1}", ex.GetType().Name, ex.Message));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
lock (eduSTARWirelessProvider._BulkLoadThreadLock)
|
|
||||||
{
|
|
||||||
eduSTARWirelessProvider._BulkLoadThread = null;
|
|
||||||
}
|
|
||||||
WirelessCertificatesLog.LogRetrievalFinished();
|
|
||||||
WirelessCertificatesLog.LogCertificateRetrievalProgress(false, null, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private DeviceCertificate LoadCertificate(int Index, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
DeviceCertificate LoadCertificate;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
WirelessCertServiceSoapClient proxy = this.GetProxy();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
LoadCertificate = this.LoadCertificate(Index, proxy, dbContext);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
bool flag = proxy != null;
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)proxy).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateError(Index.ToString(), string.Format("[{0}] {1}", ex.GetType().Name, ex.Message));
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
return LoadCertificate;
|
|
||||||
}
|
|
||||||
private DeviceCertificate LoadCertificate(int Index, WirelessCertServiceSoapClient Proxy, DiscoDataContext dbContext)
|
|
||||||
{
|
|
||||||
bool flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount SchoolId");
|
|
||||||
}
|
|
||||||
flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountUsername);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount Username");
|
|
||||||
}
|
|
||||||
flag = string.IsNullOrWhiteSpace(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountPassword);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
throw new System.ArgumentException("Wireless Certificates: Invalid ServiceAccount Password");
|
|
||||||
}
|
|
||||||
DeviceCertificate cert = new DeviceCertificate
|
|
||||||
{
|
|
||||||
ProviderIndex = Index,
|
|
||||||
Name = string.Format("{0}-{1}", dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId, Index.ToString("00000")),
|
|
||||||
Enabled = true
|
|
||||||
};
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateStarting(cert.Name);
|
|
||||||
string response;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response = Proxy.GetWirelessCert(dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountSchoolId, cert.Name, "password", dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountUsername, dbContext.DiscoConfiguration.Wireless.eduSTAR_ServiceAccountPassword);
|
|
||||||
}
|
|
||||||
catch (System.Exception ex)
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateError(cert.Name, ex.Message);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
byte[] responseBytes = System.Convert.FromBase64String(response);
|
|
||||||
System.IO.MemoryStream responseByteStream = new System.IO.MemoryStream(responseBytes);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ZipFile responseZip = ZipFile.Read(responseByteStream);
|
|
||||||
ZipEntry certFile = responseZip.FirstOrDefault((ZipEntry ze) => ze.FileName.EndsWith(".pfx", System.StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
System.IO.MemoryStream certByteStream = new System.IO.MemoryStream();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
certFile.Extract(certByteStream);
|
|
||||||
cert.Content = certByteStream.ToArray();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
flag = (certByteStream != null);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)certByteStream).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
flag = (responseByteStream != null);
|
|
||||||
if (flag)
|
|
||||||
{
|
|
||||||
((System.IDisposable)responseByteStream).Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (System.Exception ex2)
|
|
||||||
{
|
|
||||||
if (response.Contains("Computer with this name already exists"))
|
|
||||||
{
|
|
||||||
WirelessCertificatesLog.LogRetrievalCertificateWarning(cert.Name, "Already exists on eduSTAR server, disabling and skipping.");
|
|
||||||
cert.ExpirationDate = System.DateTime.Now;
|
|
||||||
cert.Enabled = false;
|
|
||||||
cert.Content = null;
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
throw new System.InvalidOperationException(string.Format("Unable to Uncompress (Server returned: {0})", response), ex2);
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
X509Certificate2 x509Cert = new X509Certificate2(cert.Content, "password");
|
|
||||||
cert.ExpirationDate = x509Cert.NotAfter;
|
|
||||||
}
|
|
||||||
catch (System.Exception ex3)
|
|
||||||
{
|
|
||||||
throw new System.InvalidOperationException("Invalid Certificate returned by Server", ex3);
|
|
||||||
}
|
|
||||||
return cert;
|
|
||||||
}
|
|
||||||
private WirelessCertServiceSoapClient GetProxy()
|
|
||||||
{
|
|
||||||
BasicHttpBinding binding = new BasicHttpBinding();
|
|
||||||
|
|
||||||
// Don't Use Proxy
|
|
||||||
binding.UseDefaultWebProxy = false;
|
|
||||||
binding.ProxyAddress = null;
|
|
||||||
|
|
||||||
binding.Security.Mode = BasicHttpSecurityMode.Transport;
|
|
||||||
binding.MaxReceivedMessageSize = 524288L;
|
|
||||||
binding.ReaderQuotas.MaxStringContentLength = 524288;
|
|
||||||
EndpointAddress endpointAddress = new EndpointAddress(new Uri("https://www.eduweb.vic.gov.au/edustar/WirelessCertWS/wirelesscertws.asmx"), new AddressHeader[0]);
|
|
||||||
return new WirelessCertServiceSoapClient(binding, endpointAddress);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -46,10 +46,6 @@
|
|||||||
<Reference Include="itextsharp">
|
<Reference Include="itextsharp">
|
||||||
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="LumenWorks.Framework.IO, Version=3.8.0.0, Culture=neutral, PublicKeyToken=5ad3ea2f85776344, processorArchitecture=MSIL">
|
|
||||||
<SpecificVersion>False</SpecificVersion>
|
|
||||||
<HintPath>..\Resources\Libraries\LumenWorks.Framework.IO\LumenWorks.Framework.IO.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||||
@@ -124,9 +120,6 @@
|
|||||||
<Compile Include="BI\AttachmentBI\Utilities.cs" />
|
<Compile Include="BI\AttachmentBI\Utilities.cs" />
|
||||||
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
||||||
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
||||||
<Compile Include="BI\DeviceBI\Importing\Import.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\ImportParseTask.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Importing\ImportProcessTask.cs" />
|
|
||||||
<Compile Include="BI\DeviceBI\Migration\LogMacAddressImporting.cs" />
|
<Compile Include="BI\DeviceBI\Migration\LogMacAddressImporting.cs" />
|
||||||
<Compile Include="BI\DisposableImageCollection.cs" />
|
<Compile Include="BI\DisposableImageCollection.cs" />
|
||||||
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
||||||
@@ -242,7 +235,7 @@
|
|||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<VisualStudio>
|
||||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
|
||||||
</VisualStudio>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||||
|
|||||||
@@ -105,6 +105,10 @@
|
|||||||
<Compile Include="Services\Devices\Exporting\DeviceExportResult.cs" />
|
<Compile Include="Services\Devices\Exporting\DeviceExportResult.cs" />
|
||||||
<Compile Include="Services\Devices\Exporting\DeviceExportTypes.cs" />
|
<Compile Include="Services\Devices\Exporting\DeviceExportTypes.cs" />
|
||||||
<Compile Include="Services\Devices\Exporting\DeviceExportOptions.cs" />
|
<Compile Include="Services\Devices\Exporting\DeviceExportOptions.cs" />
|
||||||
|
<Compile Include="Services\Devices\Importing\DeviceImportFieldTypes.cs" />
|
||||||
|
<Compile Include="Services\Devices\Importing\IDeviceImportRecord.cs" />
|
||||||
|
<Compile Include="Services\Devices\Importing\IDeviceImportContext.cs" />
|
||||||
|
<Compile Include="Services\Devices\Importing\IDeviceImportField.cs" />
|
||||||
<Compile Include="Services\Jobs\JobLists\JobLocationReference.cs" />
|
<Compile Include="Services\Jobs\JobLists\JobLocationReference.cs" />
|
||||||
<Compile Include="Services\Jobs\JobLists\JobTableItemModel.cs" />
|
<Compile Include="Services\Jobs\JobLists\JobTableItemModel.cs" />
|
||||||
<Compile Include="Services\Jobs\JobLists\JobTableModel.cs" />
|
<Compile Include="Services\Jobs\JobLists\JobTableModel.cs" />
|
||||||
@@ -151,6 +155,7 @@
|
|||||||
<Compile Include="UI\Config\Organisation\ConfigOrganisationIndexModel.cs" />
|
<Compile Include="UI\Config\Organisation\ConfigOrganisationIndexModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceAddOfflineModel.cs" />
|
<Compile Include="UI\Device\DeviceAddOfflineModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceExportModel.cs" />
|
<Compile Include="UI\Device\DeviceExportModel.cs" />
|
||||||
|
<Compile Include="UI\Device\DeviceImportHeadersModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceImportModel.cs" />
|
<Compile Include="UI\Device\DeviceImportModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceImportReviewModel.cs" />
|
<Compile Include="UI\Device\DeviceImportReviewModel.cs" />
|
||||||
<Compile Include="UI\Device\DeviceIndexModel.cs" />
|
<Compile Include="UI\Device\DeviceIndexModel.cs" />
|
||||||
@@ -166,9 +171,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Services\Devices\Importing\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<VisualStudio>
|
||||||
|
|||||||
@@ -83,19 +83,19 @@ namespace Disco.Models.Services.Devices.Exporting
|
|||||||
public bool ProfileShortName { get; set; }
|
public bool ProfileShortName { get; set; }
|
||||||
|
|
||||||
// User
|
// User
|
||||||
[Display(ShortName = "Assigned User", Name = "Identifier", Description = "The identifier of the user assigned with the device")]
|
[Display(ShortName = "Assigned User", Name = "Identifier", Description = "The identifier of the user assigned to the device")]
|
||||||
public bool AssignedUserId { get; set; }
|
public bool AssignedUserId { get; set; }
|
||||||
[Display(ShortName = "Assigned User", Name = "Assigned Date", Description = "The date the device was assigned to the user")]
|
[Display(ShortName = "Assigned User", Name = "Assigned Date", Description = "The date the device was assigned to the user")]
|
||||||
public bool AssignedUserDate { get; set; }
|
public bool AssignedUserDate { get; set; }
|
||||||
[Display(ShortName = "Assigned User", Name = "Display Name", Description = "The display name of the user assigned with the device")]
|
[Display(ShortName = "Assigned User", Name = "Display Name", Description = "The display name of the user assigned to the device")]
|
||||||
public bool AssignedUserDisplayName { get; set; }
|
public bool AssignedUserDisplayName { get; set; }
|
||||||
[Display(ShortName = "Assigned User", Name = "Surname", Description = "The surname of the user assigned with the device")]
|
[Display(ShortName = "Assigned User", Name = "Surname", Description = "The surname of the user assigned to the device")]
|
||||||
public bool AssignedUserSurname { get; set; }
|
public bool AssignedUserSurname { get; set; }
|
||||||
[Display(ShortName = "Assigned User", Name = "Given Name", Description = "The given name of the user assigned with the device")]
|
[Display(ShortName = "Assigned User", Name = "Given Name", Description = "The given name of the user assigned to the device")]
|
||||||
public bool AssignedUserGivenName { get; set; }
|
public bool AssignedUserGivenName { get; set; }
|
||||||
[Display(ShortName = "Assigned User", Name = "Phone Number", Description = "The phone number of the user assigned with the device")]
|
[Display(ShortName = "Assigned User", Name = "Phone Number", Description = "The phone number of the user assigned to the device")]
|
||||||
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 with 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; }
|
||||||
|
|
||||||
// Jobs
|
// Jobs
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public enum DeviceImportFieldTypes
|
||||||
|
{
|
||||||
|
[Required, Display(Name = "Device Serial Number", Description = "The device serial number")]
|
||||||
|
DeviceSerialNumber,
|
||||||
|
[Display(Name = "Device Asset Number", Description = "The device asset number")]
|
||||||
|
DeviceAssetNumber,
|
||||||
|
[Display(Name = "Device Location", Description = "The device location")]
|
||||||
|
DeviceLocation,
|
||||||
|
[Display(Name = "Device Decommissioned Date", Description = "The date the device was decommissioned in Disco")]
|
||||||
|
DeviceDecommissionedDate,
|
||||||
|
[Display(Name = "Device Decommissioned Reason", Description = "The reason the device was decommissioned")]
|
||||||
|
DeviceDecommissionedReason,
|
||||||
|
|
||||||
|
[Display(Name = "Device LAN MAC Address", Description = "The LAN MAC Address associated with the device")]
|
||||||
|
DetailLanMacAddress,
|
||||||
|
[Display(Name = "Device Wireless LAN MAC Address", Description = "The Wireless LAN MAC Address associated with the device")]
|
||||||
|
DetailWLanMacAddress,
|
||||||
|
[Display(Name = "Device AC Adapter", Description = "The AC Adapter associated with the device")]
|
||||||
|
DetailACAdapter,
|
||||||
|
|
||||||
|
[Display(Name = "Model Identifier", Description = "The identifier of the device model associated with the device")]
|
||||||
|
ModelId,
|
||||||
|
|
||||||
|
[Display(Name = "Batch Identifier", Description = "The identifier of the device batch associated with the device")]
|
||||||
|
BatchId,
|
||||||
|
|
||||||
|
[Display(Name = "Profile Identifier", Description = "The identifier of the device profile associated with the device")]
|
||||||
|
ProfileId,
|
||||||
|
|
||||||
|
[Display(Name = "Assigned User Identifier", Description = "The identifier of the user assigned to the device")]
|
||||||
|
AssignedUserId,
|
||||||
|
|
||||||
|
[Display(Name = "Ignore Column", Description = "The column will be ignored during the import")]
|
||||||
|
IgnoreColumn
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public interface IDeviceImportContext
|
||||||
|
{
|
||||||
|
string SessionId { get; }
|
||||||
|
string Filename { get; }
|
||||||
|
List<Tuple<string, DeviceImportFieldTypes>> Header { get; }
|
||||||
|
List<Tuple<string, DeviceImportFieldTypes, Func<string[], string>, Type>> ParsedHeaders { get; }
|
||||||
|
List<string[]> RawData { get; }
|
||||||
|
|
||||||
|
List<IDeviceImportRecord> Records { get; }
|
||||||
|
int AffectedRecords { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public interface IDeviceImportField
|
||||||
|
{
|
||||||
|
DeviceImportFieldTypes FieldType { get; }
|
||||||
|
EntityState? FieldAction { get; }
|
||||||
|
|
||||||
|
string ErrorMessage { get; }
|
||||||
|
|
||||||
|
object RawParsedValue { get; }
|
||||||
|
string FriendlyValue { get; }
|
||||||
|
string FriendlyPreviousValue { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Models.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public interface IDeviceImportRecord
|
||||||
|
{
|
||||||
|
string DeviceSerialNumber { get; }
|
||||||
|
|
||||||
|
IEnumerable<IDeviceImportField> Fields { get; }
|
||||||
|
|
||||||
|
EntityState RecordAction { get; }
|
||||||
|
|
||||||
|
bool HasError { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
|
||||||
|
namespace Disco.Models.UI.Device
|
||||||
|
{
|
||||||
|
public interface DeviceImportHeadersModel : BaseUIModel
|
||||||
|
{
|
||||||
|
IDeviceImportContext Context { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
using Disco.Models.BI.Device;
|
using Disco.Models.Services.Devices.Importing;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Disco.Models.UI.Device
|
namespace Disco.Models.UI.Device
|
||||||
{
|
{
|
||||||
public interface DeviceImportReviewModel : BaseUIModel
|
public interface DeviceImportReviewModel : BaseUIModel
|
||||||
{
|
{
|
||||||
string ImportParseTaskId { get; set; }
|
IDeviceImportContext Context { get; set; }
|
||||||
string ImportFilename { get; set; }
|
|
||||||
List<ImportDevice> ImportDevices { get; set; }
|
int StatisticErrorRecords { get; set; }
|
||||||
|
int StatisticNewRecords { get; set; }
|
||||||
|
int StatisticModifiedRecords { get; set; }
|
||||||
|
int StatisticUnmodifiedRecords { get; set; }
|
||||||
|
int StatisticImportRecords { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,199 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
using Disco.Services.Devices.Importing.Fields;
|
||||||
|
using Disco.Services.Tasks;
|
||||||
|
using LumenWorks.Framework.IO.Csv;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public static class DeviceImport
|
||||||
|
{
|
||||||
|
|
||||||
|
internal static Lazy<Dictionary<DeviceImportFieldTypes, Type>> FieldHandlers = new Lazy<Dictionary<DeviceImportFieldTypes, Type>>(() =>
|
||||||
|
{
|
||||||
|
return new Dictionary<DeviceImportFieldTypes, Type>()
|
||||||
|
{
|
||||||
|
{ DeviceImportFieldTypes.DeviceSerialNumber, typeof(DeviceSerialNumberImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DeviceAssetNumber, typeof(DeviceAssetNumberImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DeviceLocation, typeof(DeviceLocationImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DeviceDecommissionedDate, typeof(DeviceDecommissionedDateImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DeviceDecommissionedReason, typeof(DeviceDecommissionedReasonImportField) },
|
||||||
|
|
||||||
|
{ DeviceImportFieldTypes.DetailLanMacAddress, typeof(DetailLanMacAddressImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DetailWLanMacAddress, typeof(DetailWLanMacAddressImportField) },
|
||||||
|
{ DeviceImportFieldTypes.DetailACAdapter, typeof(DetailACAdapterImportField) },
|
||||||
|
|
||||||
|
{ DeviceImportFieldTypes.ModelId, typeof(ModelIdImportField) },
|
||||||
|
|
||||||
|
{ DeviceImportFieldTypes.BatchId, typeof(BatchIdImportField) },
|
||||||
|
|
||||||
|
{ DeviceImportFieldTypes.ProfileId, typeof(ProfileIdImportField) },
|
||||||
|
|
||||||
|
{ DeviceImportFieldTypes.AssignedUserId, typeof(AssignedUserIdImportField) }
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
public static DeviceImportContext BeginImport(DiscoDataContext Database, string Filename, bool HasHeader, Stream FileContent)
|
||||||
|
{
|
||||||
|
if (FileContent == null)
|
||||||
|
throw new ArgumentNullException("FileContent");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(Filename))
|
||||||
|
Filename = "<None Specified>";
|
||||||
|
|
||||||
|
DeviceImportContext context;
|
||||||
|
List<Tuple<string, DeviceImportFieldTypes>> header;
|
||||||
|
List<string[]> rawData;
|
||||||
|
|
||||||
|
using (TextReader csvTextReader = new StreamReader(FileContent))
|
||||||
|
{
|
||||||
|
using (CsvReader csvReader = new CsvReader(csvTextReader, HasHeader))
|
||||||
|
{
|
||||||
|
csvReader.DefaultParseErrorAction = ParseErrorAction.ThrowException;
|
||||||
|
csvReader.MissingFieldAction = MissingFieldAction.ReplaceByNull;
|
||||||
|
|
||||||
|
rawData = csvReader.ToList();
|
||||||
|
header = csvReader.GetFieldHeaders().Select(h => Tuple.Create(h, DeviceImportFieldTypes.IgnoreColumn)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context = new DeviceImportContext(Filename, header, rawData);
|
||||||
|
|
||||||
|
context.GuessHeaderTypes(Database);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void GuessHeaderTypes(this DeviceImportContext Context, DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
FieldHandlers.Value.ToList().ForEach(h =>
|
||||||
|
{
|
||||||
|
var instance = (DeviceImportFieldBase)Activator.CreateInstance(h.Value);
|
||||||
|
var column = instance.GuessHeader(Database, Context);
|
||||||
|
if (column.HasValue)
|
||||||
|
Context.Header[column.Value] = Tuple.Create(Context.Header[column.Value].Item1, instance.FieldType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateHeaderTypes(this DeviceImportContext Context, List<DeviceImportFieldTypes> HeaderTypes)
|
||||||
|
{
|
||||||
|
if (HeaderTypes == null)
|
||||||
|
throw new ArgumentNullException("HeaderTypes");
|
||||||
|
|
||||||
|
if (HeaderTypes.Count != Context.Header.Count)
|
||||||
|
throw new ArgumentException("The number of Header Types supplied does not match the number of Headers", "HeaderTypes");
|
||||||
|
|
||||||
|
if (!HeaderTypes.Any(h => h == DeviceImportFieldTypes.DeviceSerialNumber))
|
||||||
|
throw new ArgumentException("At least one column must be the Device Serial Number", "HeaderTypes");
|
||||||
|
|
||||||
|
if (HeaderTypes.Where(h => h != DeviceImportFieldTypes.IgnoreColumn).GroupBy(h => h, (k, i) => Tuple.Create(k, i.Count())).Any(g => g.Item2 > 1))
|
||||||
|
throw new ArgumentException("Column types can only be specified once for each type", "HeaderTypes");
|
||||||
|
|
||||||
|
Context.Header = Context.Header.Zip(HeaderTypes, (h, ht) => Tuple.Create(h.Item1, ht)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ParseRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskBasicStatus Status)
|
||||||
|
{
|
||||||
|
if (Context.Header == null)
|
||||||
|
throw new InvalidOperationException("The Import Context has not been initialized");
|
||||||
|
|
||||||
|
if (Context.Header.Count == 0)
|
||||||
|
throw new InvalidOperationException("No Headers were found");
|
||||||
|
|
||||||
|
if (!Context.Header.Any(h => h.Item2 == DeviceImportFieldTypes.DeviceSerialNumber))
|
||||||
|
throw new ArgumentException("At least one column must be the Device Serial Number", "Header");
|
||||||
|
|
||||||
|
if (Context.RawData == null || Context.RawData.Count == 0)
|
||||||
|
throw new ArgumentException("No data was found in the import file", "RawData");
|
||||||
|
|
||||||
|
IDeviceImportCache cache;
|
||||||
|
if (Context.RawData.Count > 20)
|
||||||
|
cache = new DeviceImportInMemoryCache(Database);
|
||||||
|
else
|
||||||
|
cache = new DeviceImportDatabaseCache(Database);
|
||||||
|
|
||||||
|
Context.HeaderDeviceSerialNumberIndex = Context.Header.IndexOf(Context.Header.First(h => h.Item2 == DeviceImportFieldTypes.DeviceSerialNumber));
|
||||||
|
Context.ParsedHeaders = Context.Header
|
||||||
|
.Select((h, i) => Tuple.Create(h.Item1, h.Item2, i))
|
||||||
|
.Where(h => h.Item2 != DeviceImportFieldTypes.IgnoreColumn)
|
||||||
|
.Select(h => new Tuple<string, DeviceImportFieldTypes, Func<string[], string>, Type>(h.Item1, h.Item2, (f) => f[h.Item3], DeviceImport.FieldHandlers.Value[h.Item2]))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
DateTime nextProgress = DateTime.Now;
|
||||||
|
Status.UpdateStatus(0, "Parsing Import Records", "Starting...");
|
||||||
|
|
||||||
|
Context.Records = Context.RawData.Select((d, recordIndex) =>
|
||||||
|
{
|
||||||
|
string deviceSerialNumber = Fields.DeviceSerialNumberImportField.ParseRawDeviceSerialNumber(d[Context.HeaderDeviceSerialNumberIndex]);
|
||||||
|
|
||||||
|
if (nextProgress <= DateTime.Now)
|
||||||
|
{
|
||||||
|
Status.UpdateStatus(((double)recordIndex / Context.RawData.Count) * 100, string.Format("Parsing: {0}", deviceSerialNumber));
|
||||||
|
nextProgress = DateTime.Now.AddSeconds(.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
Device existingDevice = null;
|
||||||
|
if (Fields.DeviceSerialNumberImportField.IsDeviceSerialNumberValid(deviceSerialNumber))
|
||||||
|
existingDevice = cache.Devices.FirstOrDefault(device => device.SerialNumber == deviceSerialNumber);
|
||||||
|
|
||||||
|
var values = Context.ParsedHeaders
|
||||||
|
.ToDictionary(k => k.Item2, k => k.Item3(d));
|
||||||
|
|
||||||
|
var fields = Context.ParsedHeaders.Select(h =>
|
||||||
|
{
|
||||||
|
var f = (DeviceImportFieldBase)Activator.CreateInstance(h.Item4);
|
||||||
|
f.Parse(Database, cache, Context, recordIndex, deviceSerialNumber, existingDevice, values, h.Item3(d));
|
||||||
|
return f;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
EntityState recordAction;
|
||||||
|
if (fields.Any(f => !f.FieldAction.HasValue))
|
||||||
|
recordAction = EntityState.Detached;
|
||||||
|
else if (existingDevice == null)
|
||||||
|
recordAction = EntityState.Added;
|
||||||
|
else if (fields.Any(f => f.FieldAction == EntityState.Modified))
|
||||||
|
recordAction = EntityState.Modified;
|
||||||
|
else
|
||||||
|
recordAction = EntityState.Unchanged;
|
||||||
|
|
||||||
|
return new DeviceImportRecord(deviceSerialNumber, fields, recordAction);
|
||||||
|
}).Cast<IDeviceImportRecord>().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ApplyRecords(this DeviceImportContext Context, DiscoDataContext Database, IScheduledTaskBasicStatus Status)
|
||||||
|
{
|
||||||
|
if (Context.Records == null)
|
||||||
|
throw new InvalidOperationException("Import Records have not been parsed");
|
||||||
|
|
||||||
|
if (Context.Records.Count == 0)
|
||||||
|
throw new InvalidOperationException("There are no records to import");
|
||||||
|
|
||||||
|
DateTime nextProgress = DateTime.Now;
|
||||||
|
Status.UpdateStatus(0, "Applying Import Records to Database", "Starting...");
|
||||||
|
|
||||||
|
int affectedRecords = 0;
|
||||||
|
|
||||||
|
foreach (var record in Context.Records.Cast<DeviceImportRecord>().Select((r, i) => Tuple.Create(r, i)))
|
||||||
|
{
|
||||||
|
if (nextProgress <= DateTime.Now)
|
||||||
|
{
|
||||||
|
Status.UpdateStatus(((double)record.Item2 / Context.Records.Count) * 100, string.Format("Applying: {0}", record.Item1.DeviceSerialNumber));
|
||||||
|
nextProgress = DateTime.Now.AddSeconds(.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record.Item1.Apply(Database))
|
||||||
|
affectedRecords++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return affectedRecords;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Services.Tasks;
|
||||||
|
using Quartz;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public class DeviceImportApplyTask : ScheduledTask
|
||||||
|
{
|
||||||
|
private const string JobDataMapContext = "Context";
|
||||||
|
|
||||||
|
public override string TaskName { get { return "Import Devices - Applying Changes"; } }
|
||||||
|
public override bool SingleInstanceTask { get { return false; } }
|
||||||
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
|
|
||||||
|
public static ScheduledTaskStatus ScheduleNow(DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
if (Context == null)
|
||||||
|
throw new ArgumentNullException("Context");
|
||||||
|
|
||||||
|
// Build Data Map
|
||||||
|
var task = new DeviceImportApplyTask();
|
||||||
|
JobDataMap taskData = new JobDataMap() { { JobDataMapContext, Context } };
|
||||||
|
|
||||||
|
// Schedule Task
|
||||||
|
return task.ScheduleTask(taskData);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ExecuteTask()
|
||||||
|
{
|
||||||
|
var context = (DeviceImportContext)this.ExecutionContext.JobDetail.JobDataMap[JobDataMapContext];
|
||||||
|
|
||||||
|
using (DiscoDataContext Database = new DiscoDataContext())
|
||||||
|
{
|
||||||
|
context.AffectedRecords = context.ApplyRecords(Database, this.Status);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status.SetFinishedMessage(string.Format("Successfully imported/updated {0} device{1}", context.AffectedRecords, context.AffectedRecords == 1 ? null : "s"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
using Disco.Services.Tasks;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public class DeviceImportContext : IDeviceImportContext
|
||||||
|
{
|
||||||
|
public string SessionId { get; private set; }
|
||||||
|
public string Filename { get; private set; }
|
||||||
|
|
||||||
|
public List<Tuple<string, DeviceImportFieldTypes>> Header { get; internal set; }
|
||||||
|
public List<Tuple<string, DeviceImportFieldTypes, Func<string[], string>, Type>> ParsedHeaders { get; internal set; }
|
||||||
|
internal int HeaderDeviceSerialNumberIndex { get; set; }
|
||||||
|
|
||||||
|
public List<string[]> RawData { get; private set; }
|
||||||
|
|
||||||
|
public List<IDeviceImportRecord> Records { get; internal set; }
|
||||||
|
public int AffectedRecords { get; internal set; }
|
||||||
|
|
||||||
|
internal DeviceImportContext(string Filename, List<Tuple<string, DeviceImportFieldTypes>> Header, List<string[]> RawData)
|
||||||
|
{
|
||||||
|
this.SessionId = Guid.NewGuid().ToString("D");
|
||||||
|
|
||||||
|
this.Filename = Filename;
|
||||||
|
this.Header = Header;
|
||||||
|
this.RawData = RawData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
internal class DeviceImportDatabaseCache : IDeviceImportCache
|
||||||
|
{
|
||||||
|
private DiscoDataContext Database;
|
||||||
|
|
||||||
|
public DeviceImportDatabaseCache(DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
this.Database = Database;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device FindDevice(string DeviceSerialNumber)
|
||||||
|
{
|
||||||
|
return Database.Devices.FirstOrDefault(d => d.SerialNumber == DeviceSerialNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Device> Devices
|
||||||
|
{
|
||||||
|
get { return Database.Devices; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceModel> DeviceModels
|
||||||
|
{
|
||||||
|
get { return Database.DeviceModels; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceProfile> DeviceProfiles
|
||||||
|
{
|
||||||
|
get { return Database.DeviceProfiles; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceBatch> DeviceBatches
|
||||||
|
{
|
||||||
|
get { return Database.DeviceBatches; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
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;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
internal abstract class DeviceImportFieldBase : IDeviceImportField
|
||||||
|
{
|
||||||
|
public abstract DeviceImportFieldTypes FieldType { get; }
|
||||||
|
|
||||||
|
public EntityState? FieldAction { get; protected set; }
|
||||||
|
|
||||||
|
public string ErrorMessage { get; protected set; }
|
||||||
|
|
||||||
|
public abstract object RawParsedValue { get; }
|
||||||
|
public abstract string FriendlyValue { get; }
|
||||||
|
public abstract string FriendlyPreviousValue { get; }
|
||||||
|
|
||||||
|
public abstract bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value);
|
||||||
|
public abstract bool Apply(DiscoDataContext Database, Device Device);
|
||||||
|
|
||||||
|
public abstract int? GuessHeader(DiscoDataContext Database, DeviceImportContext Context);
|
||||||
|
|
||||||
|
#region Helpers
|
||||||
|
protected bool Error(string Message)
|
||||||
|
{
|
||||||
|
this.ErrorMessage = Message;
|
||||||
|
this.FieldAction = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
protected bool Success(EntityState Action)
|
||||||
|
{
|
||||||
|
this.FieldAction = Action;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
internal class DeviceImportInMemoryCache : IDeviceImportCache
|
||||||
|
{
|
||||||
|
private DiscoDataContext Database;
|
||||||
|
|
||||||
|
private Lazy<IEnumerable<Device>> devices;
|
||||||
|
private Lazy<IEnumerable<DeviceModel>> deviceModels;
|
||||||
|
private Lazy<IEnumerable<DeviceProfile>> deviceProfiles;
|
||||||
|
private Lazy<IEnumerable<DeviceBatch>> deviceBatches;
|
||||||
|
|
||||||
|
public DeviceImportInMemoryCache(DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
this.Database = Database;
|
||||||
|
|
||||||
|
this.devices = new Lazy<IEnumerable<Device>>(() => Database.Devices.Include("DeviceDetails").ToList());
|
||||||
|
this.deviceModels = new Lazy<IEnumerable<DeviceModel>>(() => Database.DeviceModels.ToList());
|
||||||
|
this.deviceProfiles = new Lazy<IEnumerable<DeviceProfile>>(() => Database.DeviceProfiles.ToList());
|
||||||
|
this.deviceBatches = new Lazy<IEnumerable<DeviceBatch>>(() => Database.DeviceBatches.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Device FindDevice(string DeviceSerialNumber)
|
||||||
|
{
|
||||||
|
return devices.Value.FirstOrDefault(d => d.SerialNumber.Equals(DeviceSerialNumber, StringComparison.OrdinalIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Device> Devices
|
||||||
|
{
|
||||||
|
get { return devices.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceModel> DeviceModels
|
||||||
|
{
|
||||||
|
get { return deviceModels.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceProfile> DeviceProfiles
|
||||||
|
{
|
||||||
|
get { return deviceProfiles.Value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<DeviceBatch> DeviceBatches
|
||||||
|
{
|
||||||
|
get { return deviceBatches.Value; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Services.Tasks;
|
||||||
|
using Quartz;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
public class DeviceImportParseTask : ScheduledTask
|
||||||
|
{
|
||||||
|
private const string JobDataMapContext = "Context";
|
||||||
|
|
||||||
|
public override string TaskName { get { return "Import Devices - Parsing Records"; } }
|
||||||
|
public override bool SingleInstanceTask { get { return false; } }
|
||||||
|
public override bool CancelInitiallySupported { get { return false; } }
|
||||||
|
|
||||||
|
public static ScheduledTaskStatus ScheduleNow(DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
if (Context == null)
|
||||||
|
throw new ArgumentNullException("Context");
|
||||||
|
|
||||||
|
// Build Data Map
|
||||||
|
var task = new DeviceImportParseTask();
|
||||||
|
JobDataMap taskData = new JobDataMap() { { JobDataMapContext, Context } };
|
||||||
|
|
||||||
|
// Schedule Task
|
||||||
|
return task.ScheduleTask(taskData);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ExecuteTask()
|
||||||
|
{
|
||||||
|
var context = (DeviceImportContext)this.ExecutionContext.JobDetail.JobDataMap[JobDataMapContext];
|
||||||
|
|
||||||
|
using (DiscoDataContext Database = new DiscoDataContext())
|
||||||
|
{
|
||||||
|
context.ParseRecords(Database, this.Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
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;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
internal class DeviceImportRecord : IDeviceImportRecord
|
||||||
|
{
|
||||||
|
public string DeviceSerialNumber { get; private set; }
|
||||||
|
|
||||||
|
public IEnumerable<IDeviceImportField> Fields { get; private set; }
|
||||||
|
|
||||||
|
public EntityState RecordAction { get; private set; }
|
||||||
|
|
||||||
|
public bool HasError
|
||||||
|
{
|
||||||
|
get { return Fields.Any(f => !f.FieldAction.HasValue); }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal DeviceImportRecord(string DeviceSerialNumber, IEnumerable<IDeviceImportField> Fields, EntityState RecordAction)
|
||||||
|
{
|
||||||
|
this.DeviceSerialNumber = DeviceSerialNumber;
|
||||||
|
this.Fields = Fields;
|
||||||
|
this.RecordAction = RecordAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Apply(DiscoDataContext Database)
|
||||||
|
{
|
||||||
|
if (RecordAction == EntityState.Detached || !HasError)
|
||||||
|
{
|
||||||
|
Device device;
|
||||||
|
|
||||||
|
if (RecordAction == EntityState.Unchanged)
|
||||||
|
{
|
||||||
|
// Unchanged - No Action Required
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (RecordAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
device = Database.Devices.Find(this.DeviceSerialNumber);
|
||||||
|
}
|
||||||
|
else if (RecordAction == EntityState.Added)
|
||||||
|
{
|
||||||
|
// Create Device
|
||||||
|
device = new Device()
|
||||||
|
{
|
||||||
|
SerialNumber = DeviceSerialNumber.ToUpper(),
|
||||||
|
CreatedDate = DateTime.Now,
|
||||||
|
AllowUnauthenticatedEnrol = true,
|
||||||
|
DeviceProfileId = Database.DiscoConfiguration.DeviceProfiles.DefaultAddDeviceOfflineDeviceProfileId,
|
||||||
|
DeviceModelId = 1 // Default 'Unknown Device Model'
|
||||||
|
};
|
||||||
|
Database.Devices.Add(device);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid State
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool changesMade = false;
|
||||||
|
|
||||||
|
foreach (var field in Fields.Cast<DeviceImportFieldBase>())
|
||||||
|
{
|
||||||
|
changesMade = field.Apply(Database, device) || changesMade;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Commit Changes
|
||||||
|
if (changesMade)
|
||||||
|
Database.SaveChanges();
|
||||||
|
|
||||||
|
return changesMade;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record has Errors
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
using Disco.Data.Repository;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
internal class AssignedUserIdImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string friendlyValue;
|
||||||
|
private string friendlyPreviousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.AssignedUserId; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return friendlyValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return friendlyPreviousValue; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
friendlyValue = Value;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
{
|
||||||
|
friendlyValue = null;
|
||||||
|
parsedValue = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedValue = Value.Trim();
|
||||||
|
|
||||||
|
if (!parsedValue.Contains('\\'))
|
||||||
|
parsedValue = string.Format(@"{0}\{1}", Interop.ActiveDirectory.ActiveDirectory.Context.PrimaryDomain.NetBiosName, parsedValue);
|
||||||
|
|
||||||
|
friendlyValue = parsedValue;
|
||||||
|
|
||||||
|
if (parsedValue.Length > 50)
|
||||||
|
return Error("Cannot be more than 50 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedValue != null)
|
||||||
|
{
|
||||||
|
// Check User Exists
|
||||||
|
|
||||||
|
// Try Database
|
||||||
|
User user = Database.Users.FirstOrDefault(u => u.UserId == parsedValue);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Try Updating from AD
|
||||||
|
user = UserService.GetUser(parsedValue, Database);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
if (user == null)
|
||||||
|
return Error(ex.Message);
|
||||||
|
}
|
||||||
|
parsedValue = user.UserId;
|
||||||
|
friendlyValue = string.Format("{0} [{1}]", user.DisplayName, user.UserId);
|
||||||
|
|
||||||
|
// Check Decommissioned
|
||||||
|
bool? importDecommissioning = null;
|
||||||
|
if (Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedDate) || Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedReason))
|
||||||
|
importDecommissioning = Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedDate) && !string.IsNullOrWhiteSpace(Values[DeviceImportFieldTypes.DeviceDecommissionedDate]) ||
|
||||||
|
Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedReason) && !string.IsNullOrWhiteSpace(Values[DeviceImportFieldTypes.DeviceDecommissionedReason]);
|
||||||
|
|
||||||
|
if (importDecommissioning.HasValue && importDecommissioning.Value)
|
||||||
|
return Error("Cannot assign a user to a device being decommissioned");
|
||||||
|
|
||||||
|
if (ExistingDevice != null && ExistingDevice.DecommissionedDate.HasValue && !importDecommissioning.HasValue)
|
||||||
|
{
|
||||||
|
return Error("Cannot assign a user to a decommissioned device");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExistingDevice == null && parsedValue != null)
|
||||||
|
{
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
}
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.AssignedUserId != parsedValue)
|
||||||
|
{
|
||||||
|
if (ExistingDevice.AssignedUserId != null)
|
||||||
|
friendlyPreviousValue = string.Format("{0} [{1}]", ExistingDevice.AssignedUser.DisplayName, ExistingDevice.AssignedUser.UserId);
|
||||||
|
else
|
||||||
|
friendlyPreviousValue = null;
|
||||||
|
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
// Remove Current Assignments
|
||||||
|
var currentAssignments = Device.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue);
|
||||||
|
foreach (var currentAssignment in currentAssignments)
|
||||||
|
{
|
||||||
|
currentAssignment.UnassignedDate = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add Assignment
|
||||||
|
if (parsedValue != null)
|
||||||
|
{
|
||||||
|
var assignment = new DeviceUserAssignment()
|
||||||
|
{
|
||||||
|
Device = Device,
|
||||||
|
DeviceSerialNumber = Device.SerialNumber,
|
||||||
|
AssignedUserId = parsedValue,
|
||||||
|
AssignedDate = DateTime.Now
|
||||||
|
};
|
||||||
|
Database.DeviceUserAssignments.Add(assignment);
|
||||||
|
}
|
||||||
|
Device.AssignedUserId = 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("user id", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("userid", System.StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
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 BatchIdImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private int? parsedValue;
|
||||||
|
private string friendlyValue;
|
||||||
|
private string friendlyPreviousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.BatchId; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return friendlyValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return friendlyPreviousValue; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
friendlyValue = Value;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
this.parsedValue = null; // Default = null
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int valueInt;
|
||||||
|
if (int.TryParse(Value, out valueInt))
|
||||||
|
this.parsedValue = valueInt;
|
||||||
|
else
|
||||||
|
return Error("The Batch Identifier must be a number");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.parsedValue.HasValue)
|
||||||
|
{
|
||||||
|
var b = Cache.DeviceBatches.FirstOrDefault(db => db.Id == parsedValue);
|
||||||
|
if (b == null)
|
||||||
|
return Error(string.Format("The identifier ({0}) does not match any Device Batch", Value));
|
||||||
|
friendlyValue = string.Format("{0} [{1}]", b.Name, b.Id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
friendlyValue = null;
|
||||||
|
|
||||||
|
if (ExistingDevice == null)
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.DeviceBatchId != parsedValue)
|
||||||
|
{
|
||||||
|
DeviceBatch previousBatch = null;
|
||||||
|
if (ExistingDevice.DeviceBatchId.HasValue)
|
||||||
|
previousBatch = Cache.DeviceBatches.FirstOrDefault(db => db.Id == ExistingDevice.DeviceBatchId.Value);
|
||||||
|
|
||||||
|
if (previousBatch != null)
|
||||||
|
friendlyPreviousValue = string.Format("{0} [{1}]", previousBatch.Name, previousBatch.Id);
|
||||||
|
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Added ||
|
||||||
|
this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
Device.DeviceBatchId = this.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("batch", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
// All Integers Numbers
|
||||||
|
possibleColumns = possibleColumns.Where(h =>
|
||||||
|
{
|
||||||
|
int lastValue;
|
||||||
|
return Context.RawData.Select(v => v[h.Item2]).Take(100).Where(v => !string.IsNullOrWhiteSpace(v)).All(v => int.TryParse(v, out lastValue));
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Multiple Columns, tighten column definition
|
||||||
|
if (possibleColumns.Count() > 1)
|
||||||
|
{
|
||||||
|
possibleColumns = possibleColumns
|
||||||
|
.Where(h =>
|
||||||
|
h.Item1.Item1.IndexOf("batchid", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("batch id", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
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 DetailACAdapterImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string previousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DetailACAdapter; } }
|
||||||
|
|
||||||
|
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<DeviceImportFieldTypes, string> 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.HardwareKeyACAdapter);
|
||||||
|
|
||||||
|
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.HardwareKeyACAdapter);
|
||||||
|
|
||||||
|
if (detail == null)
|
||||||
|
{
|
||||||
|
detail = new DeviceDetail()
|
||||||
|
{
|
||||||
|
Device = Device,
|
||||||
|
DeviceSerialNumber = Device.SerialNumber,
|
||||||
|
Scope = DeviceDetail.ScopeHardware,
|
||||||
|
Key = DeviceDetail.HardwareKeyACAdapter
|
||||||
|
};
|
||||||
|
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("ac adapter", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("acadapter", System.StringComparison.OrdinalIgnoreCase) >= 0));
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
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 DetailLanMacAddressImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string previousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DetailLanMacAddress; } }
|
||||||
|
|
||||||
|
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<DeviceImportFieldTypes, string> 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.HardwareKeyLanMacAddress);
|
||||||
|
|
||||||
|
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.HardwareKeyLanMacAddress);
|
||||||
|
|
||||||
|
if (detail == null)
|
||||||
|
{
|
||||||
|
detail = new DeviceDetail()
|
||||||
|
{
|
||||||
|
Device = Device,
|
||||||
|
DeviceSerialNumber = Device.SerialNumber,
|
||||||
|
Scope = DeviceDetail.ScopeHardware,
|
||||||
|
Key = DeviceDetail.HardwareKeyLanMacAddress
|
||||||
|
};
|
||||||
|
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("wlan", System.StringComparison.OrdinalIgnoreCase) < 0 &&
|
||||||
|
h.Item1.Item1.IndexOf("wireless", System.StringComparison.OrdinalIgnoreCase) < 0 && (
|
||||||
|
h.Item1.Item1.IndexOf("lan address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("lan mac", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("lan mac address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("lanaddress", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("lanmac", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("lanmacaddress", System.StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
)));
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
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 DetailWLanMacAddressImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string previousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DetailWLanMacAddress; } }
|
||||||
|
|
||||||
|
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<DeviceImportFieldTypes, string> 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.HardwareKeyWLanMacAddress);
|
||||||
|
|
||||||
|
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.HardwareKeyWLanMacAddress);
|
||||||
|
|
||||||
|
if (detail == null)
|
||||||
|
{
|
||||||
|
detail = new DeviceDetail()
|
||||||
|
{
|
||||||
|
Device = Device,
|
||||||
|
DeviceSerialNumber = Device.SerialNumber,
|
||||||
|
Scope = DeviceDetail.ScopeHardware,
|
||||||
|
Key = DeviceDetail.HardwareKeyWLanMacAddress
|
||||||
|
};
|
||||||
|
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("wireless lan mac address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wireless lan address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wireless mac address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wireless mac", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlan address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlan mac", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlan mac address", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlanaddress", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlanmac", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("wlanmacaddress", System.StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
));
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
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 DeviceAssetNumberImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string previousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DeviceAssetNumber; } }
|
||||||
|
|
||||||
|
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<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
parsedValue = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedValue = Value.Trim();
|
||||||
|
if (parsedValue.Length > 40)
|
||||||
|
return Error("Cannot be more than 40 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExistingDevice == null && parsedValue != null)
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.AssetNumber != parsedValue)
|
||||||
|
{
|
||||||
|
previousValue = ExistingDevice.AssetNumber;
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Added ||
|
||||||
|
this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
Device.AssetNumber = this.parsedValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int? GuessHeader(DiscoDataContext Database, DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
// 'asset' in column name
|
||||||
|
var possibleColumns = Context.Header
|
||||||
|
.Select((h, i) => Tuple.Create(h, i))
|
||||||
|
.Where(h => h.Item1.Item2 == DeviceImportFieldTypes.IgnoreColumn && h.Item1.Item1.IndexOf("asset", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
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.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing.Fields
|
||||||
|
{
|
||||||
|
internal class DeviceDecommissionedDateImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private const string DateFormat = "yyyy-MM-dd HH:mm:ss";
|
||||||
|
|
||||||
|
private string rawValue;
|
||||||
|
private DateTime? parsedValue;
|
||||||
|
private DateTime? previousValue;
|
||||||
|
private bool setReason { get; set; }
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DeviceDecommissionedDate; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return parsedValue.HasValue ? parsedValue.Value.ToString(DateFormat) : rawValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return previousValue.HasValue ? previousValue.Value.ToString(DateFormat) : null; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
{
|
||||||
|
rawValue = null;
|
||||||
|
parsedValue = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DateTime valueDateTime;
|
||||||
|
if (!DateTime.TryParse(Value.Trim(), CultureInfo.CurrentCulture, System.Globalization.DateTimeStyles.AssumeLocal, out valueDateTime))
|
||||||
|
{
|
||||||
|
rawValue = Value.Trim();
|
||||||
|
return Error(string.Format("Cannot parse the value as a Date/Time using {0} culture (system default).", CultureInfo.CurrentCulture.Name));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Accuracy to the second (remove any milliseconds)
|
||||||
|
parsedValue = new DateTime((valueDateTime.Ticks / 10000000L) * 10000000L);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string errorMessage;
|
||||||
|
if (parsedValue.HasValue && !CanDecommissionDevice(ExistingDevice, Values, out errorMessage))
|
||||||
|
return Error(errorMessage);
|
||||||
|
|
||||||
|
setReason = !Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedReason) ||
|
||||||
|
(parsedValue.HasValue && string.IsNullOrWhiteSpace(Values[DeviceImportFieldTypes.DeviceDecommissionedReason]));
|
||||||
|
|
||||||
|
if (ExistingDevice != null && ExistingDevice.DecommissionedDate != parsedValue)
|
||||||
|
{
|
||||||
|
previousValue = ExistingDevice.DecommissionedDate;
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
// Decommission or Recommission Device
|
||||||
|
Device.DecommissionedDate = this.parsedValue;
|
||||||
|
|
||||||
|
if (setReason)
|
||||||
|
Device.DecommissionReason = this.parsedValue.HasValue ? (DecommissionReasons?)DecommissionReasons.EndOfLife : null;
|
||||||
|
|
||||||
|
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("decommission date", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissiondate", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissioned date", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissioneddate", System.StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanDecommissionDevice(Device Device, Dictionary<DeviceImportFieldTypes, string> Values, out string ErrorMessage)
|
||||||
|
{
|
||||||
|
if (Device == null)
|
||||||
|
{
|
||||||
|
ErrorMessage = "Cannot decommission new devices";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check device is assigned (or being removed in this import)
|
||||||
|
|
||||||
|
if ((!Values.ContainsKey(DeviceImportFieldTypes.AssignedUserId) && Device.AssignedUserId != null) ||
|
||||||
|
(Values.ContainsKey(DeviceImportFieldTypes.AssignedUserId) && !string.IsNullOrWhiteSpace(Values[DeviceImportFieldTypes.AssignedUserId])))
|
||||||
|
{
|
||||||
|
if (Device.AssignedUserId != null)
|
||||||
|
ErrorMessage = string.Format("The device is assigned to a user ({0} [{1}]) and cannot be decommissioned", Device.AssignedUser.DisplayName, Device.AssignedUser.UserId);
|
||||||
|
else
|
||||||
|
ErrorMessage = string.Format("The device is being assigned to a user ({0}) and cannot be decommissioned", Values[DeviceImportFieldTypes.AssignedUserId]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check device doesn't have any open jobs
|
||||||
|
var openJobCount = Device.Jobs.Count(j => !j.ClosedDate.HasValue);
|
||||||
|
if (openJobCount > 0)
|
||||||
|
{
|
||||||
|
ErrorMessage = string.Format("The device is associated with {0} open job{1} and cannot be decommissioned", openJobCount, openJobCount == 1 ? null : "s");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorMessage = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
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.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing.Fields
|
||||||
|
{
|
||||||
|
internal class DeviceDecommissionedReasonImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string rawValue;
|
||||||
|
private DecommissionReasons? parsedValue;
|
||||||
|
private DecommissionReasons? previousValue;
|
||||||
|
private bool setDate { get; set; }
|
||||||
|
private static Lazy<Dictionary<string, DecommissionReasons>> decommissionReasonsMap = new Lazy<Dictionary<string, DecommissionReasons>>(() => BuildDecommissionReasonsMap());
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DeviceDecommissionedReason; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return parsedValue.HasValue ? parsedValue.Value.ToString() : rawValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return previousValue.HasValue ? previousValue.Value.ToString() : null; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
{
|
||||||
|
rawValue = null;
|
||||||
|
parsedValue = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DecommissionReasons valueReason;
|
||||||
|
if (!decommissionReasonsMap.Value.TryGetValue(Value.Trim(), out valueReason))
|
||||||
|
{
|
||||||
|
rawValue = Value.Trim();
|
||||||
|
return Error("Cannot parse the value as a Decommission Reason");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedValue = valueReason;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedValue.HasValue && !Values.ContainsKey(DeviceImportFieldTypes.DeviceDecommissionedDate))
|
||||||
|
{
|
||||||
|
string errorMessage;
|
||||||
|
if (!DeviceDecommissionedDateImportField.CanDecommissionDevice(ExistingDevice, Values, out errorMessage))
|
||||||
|
return Error(errorMessage);
|
||||||
|
|
||||||
|
setDate = true;
|
||||||
|
}
|
||||||
|
else if (parsedValue.HasValue && string.IsNullOrWhiteSpace(Values[DeviceImportFieldTypes.DeviceDecommissionedDate]))
|
||||||
|
{
|
||||||
|
setDate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExistingDevice != null && ExistingDevice.DecommissionReason != parsedValue)
|
||||||
|
{
|
||||||
|
previousValue = ExistingDevice.DecommissionReason;
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
// Decommission or Recommission Device
|
||||||
|
Device.DecommissionReason = this.parsedValue;
|
||||||
|
|
||||||
|
if (setDate)
|
||||||
|
Device.DecommissionedDate = this.parsedValue.HasValue ? (DateTime?)DateTime.Now : null;
|
||||||
|
|
||||||
|
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("decommission reason", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissionreason", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissioned reason", System.StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("decommissionedreason", System.StringComparison.OrdinalIgnoreCase) >= 0
|
||||||
|
);
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Dictionary<string, DecommissionReasons> BuildDecommissionReasonsMap()
|
||||||
|
{
|
||||||
|
return Enum.GetValues(typeof(DecommissionReasons)).Cast<DecommissionReasons>().SelectMany(r =>
|
||||||
|
{
|
||||||
|
var rCamelName = r.ToString();
|
||||||
|
var rName = string.Join(string.Empty, rCamelName.SelectMany(c => char.IsUpper(c) ? new char[] { ' ', c } : new char[] { c })).Trim();
|
||||||
|
if (rCamelName == rName)
|
||||||
|
return new Tuple<DecommissionReasons, string>[] { Tuple.Create(r, rCamelName) };
|
||||||
|
else
|
||||||
|
return new Tuple<DecommissionReasons, string>[] { Tuple.Create(r, rCamelName), Tuple.Create(r, rName) };
|
||||||
|
}).ToDictionary(k => k.Item2, v => v.Item1, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
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 DeviceLocationImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private string parsedValue;
|
||||||
|
private string previousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DeviceLocation; } }
|
||||||
|
|
||||||
|
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<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
parsedValue = null;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedValue = Value.Trim();
|
||||||
|
if (parsedValue.Length > 250)
|
||||||
|
return Error("Cannot be more than 250 characters");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExistingDevice == null && parsedValue != null)
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.Location != parsedValue)
|
||||||
|
{
|
||||||
|
previousValue = ExistingDevice.Location;
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Added ||
|
||||||
|
this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
Device.Location = this.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("location", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 DeviceSerialNumberImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private const int maxLength = 60;
|
||||||
|
private string parsedValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.DeviceSerialNumber; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return parsedValue; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
// Validate
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
return Error("The Device Serial Number is required");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parsedValue = Value.Trim();
|
||||||
|
if (parsedValue.Length > maxLength)
|
||||||
|
return Error(string.Format("Cannot be more than {0} characters", maxLength));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate
|
||||||
|
var duplicate = Context.RawData
|
||||||
|
.Take(RecordIndex)
|
||||||
|
.Select((r, i) => Tuple.Create(i, ParseRawDeviceSerialNumber(r[Context.HeaderDeviceSerialNumberIndex])))
|
||||||
|
.Where(r => IsDeviceSerialNumberValid(r.Item2))
|
||||||
|
.FirstOrDefault(r => r.Item2.Equals(parsedValue, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (duplicate != null)
|
||||||
|
return Error(string.Format("This Device Serial Number was already present on Row {0}", duplicate.Item1 + 1));
|
||||||
|
|
||||||
|
// No action required
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
// Do nothing for Device Serial Number
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int? GuessHeader(DiscoDataContext Database, DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
// 'serial' in column name
|
||||||
|
var possibleColumns = Context.Header
|
||||||
|
.Select((h, i) => Tuple.Create(h, i))
|
||||||
|
.Where(h => h.Item1.Item2 == DeviceImportFieldTypes.IgnoreColumn && h.Item1.Item1.IndexOf("serial", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
// All Values
|
||||||
|
possibleColumns = possibleColumns.Where(h =>
|
||||||
|
{
|
||||||
|
return Context.RawData.Select(v => v[h.Item2]).All(v => !string.IsNullOrWhiteSpace(v));
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
if (possibleColumns.Count() > 1)
|
||||||
|
{
|
||||||
|
// Hunt Database
|
||||||
|
var possibleColumnIndex = possibleColumns.Where(h =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var top50SerialNumbers = Context.RawData.Select(v => v[h.Item2]).Take(50).ToArray();
|
||||||
|
return Database.Devices.Count(d => top50SerialNumbers.Contains(d.SerialNumber)) > 0;
|
||||||
|
}
|
||||||
|
catch (Exception) { return false; }
|
||||||
|
}).Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
|
||||||
|
if (possibleColumnIndex.HasValue)
|
||||||
|
return possibleColumnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ParseRawDeviceSerialNumber(string DeviceSerialNumber)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(DeviceSerialNumber))
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return DeviceSerialNumber.Trim();
|
||||||
|
}
|
||||||
|
public static bool IsDeviceSerialNumberValid(string DeviceSerialNumber)
|
||||||
|
{
|
||||||
|
return DeviceSerialNumber != null && DeviceSerialNumber.Length <= maxLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 ModelIdImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private int parsedValue;
|
||||||
|
private string friendlyValue;
|
||||||
|
private string friendlyPreviousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.ModelId; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return friendlyValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return friendlyPreviousValue; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
friendlyValue = Value;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
this.parsedValue = 1; // Default Model
|
||||||
|
else
|
||||||
|
if (!int.TryParse(Value, out parsedValue))
|
||||||
|
return Error("The Model Identifier must be a number");
|
||||||
|
|
||||||
|
var m = Cache.DeviceModels.FirstOrDefault(dm => dm.Id == parsedValue);
|
||||||
|
|
||||||
|
if (m == null)
|
||||||
|
return Error(string.Format("The identifier ({0}) does not match any Device Model", Value));
|
||||||
|
|
||||||
|
friendlyValue = string.Format("{0} [{1}]", m.Description, m.Id);
|
||||||
|
|
||||||
|
if (ExistingDevice == null)
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.DeviceModelId != parsedValue)
|
||||||
|
{
|
||||||
|
friendlyPreviousValue = null;
|
||||||
|
if (ExistingDevice.DeviceModelId.HasValue)
|
||||||
|
{
|
||||||
|
var previousModel = Cache.DeviceModels.FirstOrDefault(dm => dm.Id == ExistingDevice.DeviceModelId.Value);
|
||||||
|
friendlyPreviousValue = string.Format("{0} [{1}]", previousModel.Description, previousModel.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Added ||
|
||||||
|
this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
Device.DeviceModelId = this.parsedValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int? GuessHeader(DiscoDataContext Database, DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
// 'model' in column name
|
||||||
|
var possibleColumns = Context.Header
|
||||||
|
.Select((h, i) => Tuple.Create(h, i))
|
||||||
|
.Where(h => h.Item1.Item2 == DeviceImportFieldTypes.IgnoreColumn && h.Item1.Item1.IndexOf("model", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
// All Integers Numbers
|
||||||
|
possibleColumns = possibleColumns.Where(h =>
|
||||||
|
{
|
||||||
|
int lastValue;
|
||||||
|
return Context.RawData.Select(v => v[h.Item2]).Take(100).Where(v => !string.IsNullOrWhiteSpace(v)).All(v => int.TryParse(v, out lastValue));
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Multiple Columns, tighten column definition
|
||||||
|
if (possibleColumns.Count() > 1)
|
||||||
|
{
|
||||||
|
possibleColumns = possibleColumns
|
||||||
|
.Where(h =>
|
||||||
|
h.Item1.Item1.IndexOf("modelid", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("model id", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
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 ProfileIdImportField : DeviceImportFieldBase
|
||||||
|
{
|
||||||
|
private int parsedValue;
|
||||||
|
private string friendlyValue;
|
||||||
|
private string friendlyPreviousValue;
|
||||||
|
|
||||||
|
public override DeviceImportFieldTypes FieldType { get { return DeviceImportFieldTypes.ProfileId; } }
|
||||||
|
|
||||||
|
public override object RawParsedValue { get { return parsedValue; } }
|
||||||
|
public override string FriendlyValue { get { return friendlyValue; } }
|
||||||
|
public override string FriendlyPreviousValue { get { return friendlyPreviousValue; } }
|
||||||
|
|
||||||
|
public override bool Parse(DiscoDataContext Database, IDeviceImportCache Cache, DeviceImportContext Context, int RecordIndex, string DeviceSerialNumber, Device ExistingDevice, Dictionary<DeviceImportFieldTypes, string> Values, string Value)
|
||||||
|
{
|
||||||
|
friendlyValue = Value;
|
||||||
|
|
||||||
|
// Validate
|
||||||
|
if (string.IsNullOrWhiteSpace(Value))
|
||||||
|
this.parsedValue = Database.DiscoConfiguration.DeviceProfiles.DefaultAddDeviceOfflineDeviceProfileId;
|
||||||
|
else
|
||||||
|
if (!int.TryParse(Value, out parsedValue))
|
||||||
|
return Error("The Profile Identifier must be a number");
|
||||||
|
|
||||||
|
var p = Cache.DeviceProfiles.FirstOrDefault(dp => dp.Id == parsedValue);
|
||||||
|
|
||||||
|
if (p == null)
|
||||||
|
return Error(string.Format("The identifier ({0}) does not match any Device Profile", Value));
|
||||||
|
|
||||||
|
friendlyValue = string.Format("{0} [{1}]", p.Description, p.Id);
|
||||||
|
|
||||||
|
if (ExistingDevice == null)
|
||||||
|
return Success(EntityState.Added);
|
||||||
|
else if (ExistingDevice != null && ExistingDevice.DeviceProfileId != parsedValue)
|
||||||
|
{
|
||||||
|
var previousProfile = Cache.DeviceProfiles.FirstOrDefault(dp => dp.Id == ExistingDevice.DeviceProfileId);
|
||||||
|
friendlyPreviousValue = string.Format("{0} [{1}]", previousProfile.Description, previousProfile.Id);
|
||||||
|
|
||||||
|
return Success(EntityState.Modified);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return Success(EntityState.Unchanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Apply(DiscoDataContext Database, Device Device)
|
||||||
|
{
|
||||||
|
if (this.FieldAction == EntityState.Added ||
|
||||||
|
this.FieldAction == EntityState.Modified)
|
||||||
|
{
|
||||||
|
Device.DeviceProfileId = this.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("profile", System.StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
|
||||||
|
// All Integers Numbers
|
||||||
|
possibleColumns = possibleColumns.Where(h =>
|
||||||
|
{
|
||||||
|
int lastValue;
|
||||||
|
return Context.RawData.Select(v => v[h.Item2]).Take(100).Where(v => !string.IsNullOrWhiteSpace(v)).All(v => int.TryParse(v, out lastValue));
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
// Multiple Columns, tighten column definition
|
||||||
|
if (possibleColumns.Count() > 1)
|
||||||
|
{
|
||||||
|
possibleColumns = possibleColumns
|
||||||
|
.Where(h =>
|
||||||
|
h.Item1.Item1.IndexOf("profileid", StringComparison.OrdinalIgnoreCase) >= 0 ||
|
||||||
|
h.Item1.Item1.IndexOf("profile id", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleColumns.Select(h => (int?)h.Item2).FirstOrDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Disco.Models.Repository;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Disco.Services.Devices.Importing
|
||||||
|
{
|
||||||
|
internal interface IDeviceImportCache
|
||||||
|
{
|
||||||
|
Device FindDevice(string DeviceSerialNumber);
|
||||||
|
|
||||||
|
IEnumerable<Device> Devices { get; }
|
||||||
|
IEnumerable<DeviceModel> DeviceModels { get; }
|
||||||
|
IEnumerable<DeviceProfile> DeviceProfiles { get; }
|
||||||
|
IEnumerable<DeviceBatch> DeviceBatches { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,9 @@
|
|||||||
<Reference Include="EntityFramework">
|
<Reference Include="EntityFramework">
|
||||||
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
|
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="LumenWorks.Framework.IO">
|
||||||
|
<HintPath>..\packages\LumenWorks.Framework.IO.3.8.0\lib\net20\LumenWorks.Framework.IO.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
<Reference Include="Microsoft.AspNet.SignalR.Core, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||||
<SpecificVersion>False</SpecificVersion>
|
<SpecificVersion>False</SpecificVersion>
|
||||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||||
@@ -175,6 +178,27 @@
|
|||||||
<Compile Include="Devices\Exporting\DeviceExport.cs" />
|
<Compile Include="Devices\Exporting\DeviceExport.cs" />
|
||||||
<Compile Include="Devices\Exporting\DeviceExportTask.cs" />
|
<Compile Include="Devices\Exporting\DeviceExportTask.cs" />
|
||||||
<Compile Include="Devices\Exporting\DeviceExportTaskContext.cs" />
|
<Compile Include="Devices\Exporting\DeviceExportTaskContext.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImport.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportApplyTask.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportContext.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportDatabaseCache.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportFieldBase.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportInMemoryCache.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportParseTask.cs" />
|
||||||
|
<Compile Include="Devices\Importing\DeviceImportRecord.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\BatchIdImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\AssignedUserIdImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DeviceDecommissionedReasonImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DeviceDecommissionedDateImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\ProfileIdImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DetailACAdapterImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DetailWLanMacAddressImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DetailLanMacAddressImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DeviceLocationImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DeviceAssetNumberImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\DeviceSerialNumberImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\Fields\ModelIdImportField.cs" />
|
||||||
|
<Compile Include="Devices\Importing\IDeviceImportCache.cs" />
|
||||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||||
<Compile Include="Extensions\StringExtensions.cs" />
|
<Compile Include="Extensions\StringExtensions.cs" />
|
||||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
<Compile Include="Interop\ActiveDirectory\ActiveDirectory.cs" />
|
||||||
@@ -298,9 +322,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup />
|
||||||
<Folder Include="Devices\Importing\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<ProjectExtensions>
|
<ProjectExtensions>
|
||||||
<VisualStudio>
|
<VisualStudio>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<packages>
|
<packages>
|
||||||
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
||||||
|
<package id="LumenWorks.Framework.IO" version="3.8.0" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net45" />
|
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net45" />
|
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net45" />
|
||||||
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
using Disco.BI.Extensions;
|
using Disco.BI.Extensions;
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
using Disco.Services.Authorization;
|
using Disco.Services.Authorization;
|
||||||
using Disco.Services.Devices.Exporting;
|
using Disco.Services.Devices.Exporting;
|
||||||
|
using Disco.Services.Devices.Importing;
|
||||||
using Disco.Services.Interop.ActiveDirectory;
|
using Disco.Services.Interop.ActiveDirectory;
|
||||||
using Disco.Services.Users;
|
using Disco.Services.Users;
|
||||||
using Disco.Services.Web;
|
using Disco.Services.Web;
|
||||||
using Disco.Web.Models.Device;
|
using Disco.Web.Models.Device;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
@@ -530,9 +533,26 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Importing
|
#region Importing
|
||||||
|
internal const string ImportSessionCacheKey = "DeviceImportContext_{0}";
|
||||||
|
|
||||||
|
internal static void Import_StoreContext(DeviceImportContext Context)
|
||||||
|
{
|
||||||
|
string key = string.Format(ImportSessionCacheKey, Context.SessionId);
|
||||||
|
HttpRuntime.Cache.Insert(key, Context, null, DateTime.Now.AddMinutes(60), Cache.NoSlidingExpiration, CacheItemPriority.NotRemovable, null);
|
||||||
|
}
|
||||||
|
internal static DeviceImportContext Import_RetrieveContext(string SessionId, bool Remove = false)
|
||||||
|
{
|
||||||
|
string key = string.Format(ImportSessionCacheKey, SessionId);
|
||||||
|
DeviceImportContext context = HttpRuntime.Cache.Get(key) as DeviceImportContext;
|
||||||
|
|
||||||
|
if (Remove && context != null)
|
||||||
|
HttpRuntime.Cache.Remove(key);
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
[DiscoAuthorize(Claims.Device.Actions.Import)]
|
[DiscoAuthorize(Claims.Device.Actions.Import)]
|
||||||
public virtual ActionResult ImportParse(HttpPostedFileBase ImportFile)
|
public virtual ActionResult ImportBegin(HttpPostedFileBase ImportFile, bool HasHeader)
|
||||||
{
|
{
|
||||||
if (ImportFile == null || ImportFile.ContentLength == 0)
|
if (ImportFile == null || ImportFile.ContentLength == 0)
|
||||||
throw new ArgumentNullException("ImportFile");
|
throw new ArgumentNullException("ImportFile");
|
||||||
@@ -541,22 +561,50 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
if (fileName.Contains(@"\"))
|
if (fileName.Contains(@"\"))
|
||||||
fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
|
fileName = fileName.Substring(fileName.LastIndexOf('\\') + 1);
|
||||||
|
|
||||||
var status = Disco.BI.DeviceBI.Importing.ImportParseTask.Run(ImportFile.InputStream, fileName);
|
var context = DeviceImport.BeginImport(Database, fileName, HasHeader, ImportFile.InputStream);
|
||||||
|
Import_StoreContext(context);
|
||||||
|
|
||||||
status.SetFinishedUrl(Url.Action(MVC.Device.ImportReview(status.SessionId)));
|
return RedirectToAction(MVC.Device.ImportHeaders(context.SessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
[DiscoAuthorize(Claims.Device.Actions.Import)]
|
||||||
|
public virtual ActionResult ImportParse(string Id, List<DeviceImportFieldTypes> Headers)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Id))
|
||||||
|
throw new ArgumentNullException("Id");
|
||||||
|
|
||||||
|
var context = Import_RetrieveContext(Id);
|
||||||
|
|
||||||
|
if (context == null)
|
||||||
|
throw new ArgumentException("The Import Session Id is invalid or the session timed out (60 minutes), try importing again", "Id");
|
||||||
|
|
||||||
|
context.UpdateHeaderTypes(Headers);
|
||||||
|
|
||||||
|
var status = DeviceImportParseTask.ScheduleNow(context);
|
||||||
|
|
||||||
|
var finishedUrl = MVC.Device.ImportReview(context.SessionId);
|
||||||
|
|
||||||
|
status.SetFinishedUrl(Url.Action(finishedUrl));
|
||||||
|
|
||||||
|
if (status.WaitUntilFinished(TimeSpan.FromSeconds(2)))
|
||||||
|
return RedirectToAction(finishedUrl);
|
||||||
|
else
|
||||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId));
|
return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId));
|
||||||
}
|
}
|
||||||
|
|
||||||
[DiscoAuthorize(Claims.Device.Actions.Import)]
|
[DiscoAuthorize(Claims.Device.Actions.Import)]
|
||||||
public virtual ActionResult ImportProcess(string ParseTaskSessionKey)
|
public virtual ActionResult ImportApply(string Id)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(ParseTaskSessionKey))
|
if (string.IsNullOrWhiteSpace(Id))
|
||||||
throw new ArgumentNullException("ParseTaskSessionKey");
|
throw new ArgumentNullException("Id");
|
||||||
|
|
||||||
var status = Disco.BI.DeviceBI.Importing.ImportProcessTask.Run(ParseTaskSessionKey);
|
var context = Import_RetrieveContext(Id);
|
||||||
|
|
||||||
status.SetFinishedUrl(Url.Action(MVC.Device.Index()));
|
if (context == null)
|
||||||
|
throw new ArgumentException("The Import Session Id is invalid or the session timed out (60 minutes), try importing again", "Id");
|
||||||
|
|
||||||
|
var status = DeviceImportApplyTask.ScheduleNow(context);
|
||||||
|
status.SetFinishedUrl(Url.Action(MVC.Device.Import(context.SessionId)));
|
||||||
|
|
||||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId));
|
return RedirectToAction(MVC.Config.Logging.TaskStatus(status.SessionId));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1838,15 +1838,15 @@ body .ui-tooltip {
|
|||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
/*!
|
/*!
|
||||||
* Font Awesome 4.0.3 by @davegandy - http://fontawesome.io - @fontawesome
|
* Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome
|
||||||
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
|
||||||
*/
|
*/
|
||||||
/* FONT PATH
|
/* FONT PATH
|
||||||
* -------------------------- */
|
* -------------------------- */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'FontAwesome';
|
font-family: 'FontAwesome';
|
||||||
src: url('/ClientSource/Style/FontAwesome/fontawesome-webfont.eot?v=4.0.3');
|
src: url('/ClientSource/Style/FontAwesome//fontawesome-webfont.eot?v=4.1.0');
|
||||||
src: url('/ClientSource/Style/FontAwesome/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'), url('/ClientSource/Style/FontAwesome/fontawesome-webfont.woff?v=4.0.3') format('woff'), url('/ClientSource/Style/FontAwesome/fontawesome-webfont.ttf?v=4.0.3') format('truetype'), url('/ClientSource/Style/FontAwesome/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
|
src: url('/ClientSource/Style/FontAwesome//fontawesome-webfont.eot?#iefix&v=4.1.0') format('embedded-opentype'), url('/ClientSource/Style/FontAwesome//fontawesome-webfont.woff?v=4.1.0') format('woff'), url('/ClientSource/Style/FontAwesome//fontawesome-webfont.ttf?v=4.1.0') format('truetype'), url('/ClientSource/Style/FontAwesome//fontawesome-webfont.svg?v=4.1.0#fontawesomeregular') format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
@@ -1861,7 +1861,7 @@ body .ui-tooltip {
|
|||||||
}
|
}
|
||||||
/* makes the font 33% larger relative to the icon container */
|
/* makes the font 33% larger relative to the icon container */
|
||||||
.fa-lg {
|
.fa-lg {
|
||||||
font-size: 1.3333333333333333em;
|
font-size: 1.33333333em;
|
||||||
line-height: 0.75em;
|
line-height: 0.75em;
|
||||||
vertical-align: -15%;
|
vertical-align: -15%;
|
||||||
}
|
}
|
||||||
@@ -1878,12 +1878,12 @@ body .ui-tooltip {
|
|||||||
font-size: 5em;
|
font-size: 5em;
|
||||||
}
|
}
|
||||||
.fa-fw {
|
.fa-fw {
|
||||||
width: 1.2857142857142858em;
|
width: 1.28571429em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.fa-ul {
|
.fa-ul {
|
||||||
padding-left: 0;
|
padding-left: 0;
|
||||||
margin-left: 2.142857142857143em;
|
margin-left: 2.14285714em;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
}
|
}
|
||||||
.fa-ul > li {
|
.fa-ul > li {
|
||||||
@@ -1892,8 +1892,8 @@ body .ui-tooltip {
|
|||||||
.fa-li {
|
.fa-li {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: -2.14285714em;
|
left: -2.14285714em;
|
||||||
width: 2.142857142857143em;
|
width: 2.14285714em;
|
||||||
top: 0.14285714285714285em;
|
top: 0.14285714em;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
.fa-li.fa-lg {
|
.fa-li.fa-lg {
|
||||||
@@ -1946,19 +1946,13 @@ body .ui-tooltip {
|
|||||||
-o-transform: rotate(359deg);
|
-o-transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@-ms-keyframes spin {
|
|
||||||
0% {
|
|
||||||
-ms-transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-ms-transform: rotate(359deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% {
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg);
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
100% {
|
100% {
|
||||||
|
-webkit-transform: rotate(359deg);
|
||||||
transform: rotate(359deg);
|
transform: rotate(359deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2208,6 +2202,8 @@ body .ui-tooltip {
|
|||||||
.fa-video-camera:before {
|
.fa-video-camera:before {
|
||||||
content: "\f03d";
|
content: "\f03d";
|
||||||
}
|
}
|
||||||
|
.fa-photo:before,
|
||||||
|
.fa-image:before,
|
||||||
.fa-picture-o:before {
|
.fa-picture-o:before {
|
||||||
content: "\f03e";
|
content: "\f03e";
|
||||||
}
|
}
|
||||||
@@ -2571,6 +2567,8 @@ body .ui-tooltip {
|
|||||||
.fa-square:before {
|
.fa-square:before {
|
||||||
content: "\f0c8";
|
content: "\f0c8";
|
||||||
}
|
}
|
||||||
|
.fa-navicon:before,
|
||||||
|
.fa-reorder:before,
|
||||||
.fa-bars:before {
|
.fa-bars:before {
|
||||||
content: "\f0c9";
|
content: "\f0c9";
|
||||||
}
|
}
|
||||||
@@ -2630,11 +2628,11 @@ body .ui-tooltip {
|
|||||||
content: "\f0dc";
|
content: "\f0dc";
|
||||||
}
|
}
|
||||||
.fa-sort-down:before,
|
.fa-sort-down:before,
|
||||||
.fa-sort-asc:before {
|
.fa-sort-desc:before {
|
||||||
content: "\f0dd";
|
content: "\f0dd";
|
||||||
}
|
}
|
||||||
.fa-sort-up:before,
|
.fa-sort-up:before,
|
||||||
.fa-sort-desc:before {
|
.fa-sort-asc:before {
|
||||||
content: "\f0de";
|
content: "\f0de";
|
||||||
}
|
}
|
||||||
.fa-envelope:before {
|
.fa-envelope:before {
|
||||||
@@ -2824,12 +2822,10 @@ body .ui-tooltip {
|
|||||||
.fa-code:before {
|
.fa-code:before {
|
||||||
content: "\f121";
|
content: "\f121";
|
||||||
}
|
}
|
||||||
|
.fa-mail-reply-all:before,
|
||||||
.fa-reply-all:before {
|
.fa-reply-all:before {
|
||||||
content: "\f122";
|
content: "\f122";
|
||||||
}
|
}
|
||||||
.fa-mail-reply-all:before {
|
|
||||||
content: "\f122";
|
|
||||||
}
|
|
||||||
.fa-star-half-empty:before,
|
.fa-star-half-empty:before,
|
||||||
.fa-star-half-full:before,
|
.fa-star-half-full:before,
|
||||||
.fa-star-half-o:before {
|
.fa-star-half-o:before {
|
||||||
@@ -3175,6 +3171,238 @@ body .ui-tooltip {
|
|||||||
.fa-plus-square-o:before {
|
.fa-plus-square-o:before {
|
||||||
content: "\f196";
|
content: "\f196";
|
||||||
}
|
}
|
||||||
|
.fa-space-shuttle:before {
|
||||||
|
content: "\f197";
|
||||||
|
}
|
||||||
|
.fa-slack:before {
|
||||||
|
content: "\f198";
|
||||||
|
}
|
||||||
|
.fa-envelope-square:before {
|
||||||
|
content: "\f199";
|
||||||
|
}
|
||||||
|
.fa-wordpress:before {
|
||||||
|
content: "\f19a";
|
||||||
|
}
|
||||||
|
.fa-openid:before {
|
||||||
|
content: "\f19b";
|
||||||
|
}
|
||||||
|
.fa-institution:before,
|
||||||
|
.fa-bank:before,
|
||||||
|
.fa-university:before {
|
||||||
|
content: "\f19c";
|
||||||
|
}
|
||||||
|
.fa-mortar-board:before,
|
||||||
|
.fa-graduation-cap:before {
|
||||||
|
content: "\f19d";
|
||||||
|
}
|
||||||
|
.fa-yahoo:before {
|
||||||
|
content: "\f19e";
|
||||||
|
}
|
||||||
|
.fa-google:before {
|
||||||
|
content: "\f1a0";
|
||||||
|
}
|
||||||
|
.fa-reddit:before {
|
||||||
|
content: "\f1a1";
|
||||||
|
}
|
||||||
|
.fa-reddit-square:before {
|
||||||
|
content: "\f1a2";
|
||||||
|
}
|
||||||
|
.fa-stumbleupon-circle:before {
|
||||||
|
content: "\f1a3";
|
||||||
|
}
|
||||||
|
.fa-stumbleupon:before {
|
||||||
|
content: "\f1a4";
|
||||||
|
}
|
||||||
|
.fa-delicious:before {
|
||||||
|
content: "\f1a5";
|
||||||
|
}
|
||||||
|
.fa-digg:before {
|
||||||
|
content: "\f1a6";
|
||||||
|
}
|
||||||
|
.fa-pied-piper-square:before,
|
||||||
|
.fa-pied-piper:before {
|
||||||
|
content: "\f1a7";
|
||||||
|
}
|
||||||
|
.fa-pied-piper-alt:before {
|
||||||
|
content: "\f1a8";
|
||||||
|
}
|
||||||
|
.fa-drupal:before {
|
||||||
|
content: "\f1a9";
|
||||||
|
}
|
||||||
|
.fa-joomla:before {
|
||||||
|
content: "\f1aa";
|
||||||
|
}
|
||||||
|
.fa-language:before {
|
||||||
|
content: "\f1ab";
|
||||||
|
}
|
||||||
|
.fa-fax:before {
|
||||||
|
content: "\f1ac";
|
||||||
|
}
|
||||||
|
.fa-building:before {
|
||||||
|
content: "\f1ad";
|
||||||
|
}
|
||||||
|
.fa-child:before {
|
||||||
|
content: "\f1ae";
|
||||||
|
}
|
||||||
|
.fa-paw:before {
|
||||||
|
content: "\f1b0";
|
||||||
|
}
|
||||||
|
.fa-spoon:before {
|
||||||
|
content: "\f1b1";
|
||||||
|
}
|
||||||
|
.fa-cube:before {
|
||||||
|
content: "\f1b2";
|
||||||
|
}
|
||||||
|
.fa-cubes:before {
|
||||||
|
content: "\f1b3";
|
||||||
|
}
|
||||||
|
.fa-behance:before {
|
||||||
|
content: "\f1b4";
|
||||||
|
}
|
||||||
|
.fa-behance-square:before {
|
||||||
|
content: "\f1b5";
|
||||||
|
}
|
||||||
|
.fa-steam:before {
|
||||||
|
content: "\f1b6";
|
||||||
|
}
|
||||||
|
.fa-steam-square:before {
|
||||||
|
content: "\f1b7";
|
||||||
|
}
|
||||||
|
.fa-recycle:before {
|
||||||
|
content: "\f1b8";
|
||||||
|
}
|
||||||
|
.fa-automobile:before,
|
||||||
|
.fa-car:before {
|
||||||
|
content: "\f1b9";
|
||||||
|
}
|
||||||
|
.fa-cab:before,
|
||||||
|
.fa-taxi:before {
|
||||||
|
content: "\f1ba";
|
||||||
|
}
|
||||||
|
.fa-tree:before {
|
||||||
|
content: "\f1bb";
|
||||||
|
}
|
||||||
|
.fa-spotify:before {
|
||||||
|
content: "\f1bc";
|
||||||
|
}
|
||||||
|
.fa-deviantart:before {
|
||||||
|
content: "\f1bd";
|
||||||
|
}
|
||||||
|
.fa-soundcloud:before {
|
||||||
|
content: "\f1be";
|
||||||
|
}
|
||||||
|
.fa-database:before {
|
||||||
|
content: "\f1c0";
|
||||||
|
}
|
||||||
|
.fa-file-pdf-o:before {
|
||||||
|
content: "\f1c1";
|
||||||
|
}
|
||||||
|
.fa-file-word-o:before {
|
||||||
|
content: "\f1c2";
|
||||||
|
}
|
||||||
|
.fa-file-excel-o:before {
|
||||||
|
content: "\f1c3";
|
||||||
|
}
|
||||||
|
.fa-file-powerpoint-o:before {
|
||||||
|
content: "\f1c4";
|
||||||
|
}
|
||||||
|
.fa-file-photo-o:before,
|
||||||
|
.fa-file-picture-o:before,
|
||||||
|
.fa-file-image-o:before {
|
||||||
|
content: "\f1c5";
|
||||||
|
}
|
||||||
|
.fa-file-zip-o:before,
|
||||||
|
.fa-file-archive-o:before {
|
||||||
|
content: "\f1c6";
|
||||||
|
}
|
||||||
|
.fa-file-sound-o:before,
|
||||||
|
.fa-file-audio-o:before {
|
||||||
|
content: "\f1c7";
|
||||||
|
}
|
||||||
|
.fa-file-movie-o:before,
|
||||||
|
.fa-file-video-o:before {
|
||||||
|
content: "\f1c8";
|
||||||
|
}
|
||||||
|
.fa-file-code-o:before {
|
||||||
|
content: "\f1c9";
|
||||||
|
}
|
||||||
|
.fa-vine:before {
|
||||||
|
content: "\f1ca";
|
||||||
|
}
|
||||||
|
.fa-codepen:before {
|
||||||
|
content: "\f1cb";
|
||||||
|
}
|
||||||
|
.fa-jsfiddle:before {
|
||||||
|
content: "\f1cc";
|
||||||
|
}
|
||||||
|
.fa-life-bouy:before,
|
||||||
|
.fa-life-saver:before,
|
||||||
|
.fa-support:before,
|
||||||
|
.fa-life-ring:before {
|
||||||
|
content: "\f1cd";
|
||||||
|
}
|
||||||
|
.fa-circle-o-notch:before {
|
||||||
|
content: "\f1ce";
|
||||||
|
}
|
||||||
|
.fa-ra:before,
|
||||||
|
.fa-rebel:before {
|
||||||
|
content: "\f1d0";
|
||||||
|
}
|
||||||
|
.fa-ge:before,
|
||||||
|
.fa-empire:before {
|
||||||
|
content: "\f1d1";
|
||||||
|
}
|
||||||
|
.fa-git-square:before {
|
||||||
|
content: "\f1d2";
|
||||||
|
}
|
||||||
|
.fa-git:before {
|
||||||
|
content: "\f1d3";
|
||||||
|
}
|
||||||
|
.fa-hacker-news:before {
|
||||||
|
content: "\f1d4";
|
||||||
|
}
|
||||||
|
.fa-tencent-weibo:before {
|
||||||
|
content: "\f1d5";
|
||||||
|
}
|
||||||
|
.fa-qq:before {
|
||||||
|
content: "\f1d6";
|
||||||
|
}
|
||||||
|
.fa-wechat:before,
|
||||||
|
.fa-weixin:before {
|
||||||
|
content: "\f1d7";
|
||||||
|
}
|
||||||
|
.fa-send:before,
|
||||||
|
.fa-paper-plane:before {
|
||||||
|
content: "\f1d8";
|
||||||
|
}
|
||||||
|
.fa-send-o:before,
|
||||||
|
.fa-paper-plane-o:before {
|
||||||
|
content: "\f1d9";
|
||||||
|
}
|
||||||
|
.fa-history:before {
|
||||||
|
content: "\f1da";
|
||||||
|
}
|
||||||
|
.fa-circle-thin:before {
|
||||||
|
content: "\f1db";
|
||||||
|
}
|
||||||
|
.fa-header:before {
|
||||||
|
content: "\f1dc";
|
||||||
|
}
|
||||||
|
.fa-paragraph:before {
|
||||||
|
content: "\f1dd";
|
||||||
|
}
|
||||||
|
.fa-sliders:before {
|
||||||
|
content: "\f1de";
|
||||||
|
}
|
||||||
|
.fa-share-alt:before {
|
||||||
|
content: "\f1e0";
|
||||||
|
}
|
||||||
|
.fa-share-alt-square:before {
|
||||||
|
content: "\f1e1";
|
||||||
|
}
|
||||||
|
.fa-bomb:before {
|
||||||
|
content: "\f1e2";
|
||||||
|
}
|
||||||
.tableData {
|
.tableData {
|
||||||
border: solid 1px #f4f4f4;
|
border: solid 1px #f4f4f4;
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
@@ -4692,3 +4920,8 @@ input:-moz-placeholder {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
padding: .6em 1em;
|
padding: .6em 1em;
|
||||||
}
|
}
|
||||||
|
body .ui-tooltip {
|
||||||
|
border-width: 1px;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -373,95 +373,172 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
color: #1e6dab;
|
color: #1e6dab;
|
||||||
}
|
}
|
||||||
#deviceImport #ImportFile {
|
#Devices_Import #ImportFile {
|
||||||
width: 100%;
|
width: 96%;
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
#deviceImport #documentation {
|
#Devices_Import #Devices_Import_Documentation {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
}
|
}
|
||||||
#deviceImport #documentation > table > thead > tr > th:first-child {
|
#Devices_Import #Devices_Import_Documentation > table > tbody th:first-child {
|
||||||
width: 100px;
|
width: 220px;
|
||||||
}
|
}
|
||||||
#deviceImportReview #errorMessage {
|
#Devices_Import_Completed_Dialog {
|
||||||
font-weight: bold;
|
padding: 50px 0;
|
||||||
color: red;
|
text-align: center;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation {
|
#Devices_Import_Completed_Dialog h3 {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
#Devices_Import_Completed_Dialog i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #60a917;
|
||||||
|
}
|
||||||
|
#Devices_Import_Loading_Dialog {
|
||||||
|
padding-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#Devices_Import_Loading_Dialog i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #1e6dab;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer {
|
||||||
|
margin: 18px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > thead {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > thead ul.importHeaderType > li > a > span:not(.ui-menu-icon) {
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > thead ul.importHeaderType ul {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > thead td.headerIgnoreColumn {
|
||||||
|
background-color: #fa6800;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > thead td:not(.headerIgnoreColumn) {
|
||||||
|
background-color: #1e6dab;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > tbody td.headerDeviceSerialNumber {
|
||||||
|
border-top-color: #d1e6f7;
|
||||||
|
border-bottom-color: #d1e6f7;
|
||||||
|
background-color: #e2f0fa;
|
||||||
|
}
|
||||||
|
#Devices_Import_Headers #Devices_Import_Headers_TableContainer table > tbody td.headerIgnoreColumn {
|
||||||
|
max-width: 150px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
-ms-text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
#Devices_Import_Parsing_Dialog {
|
||||||
|
padding-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#Devices_Import_Parsing_Dialog i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: #1e6dab;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_Navigation {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation ul {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px;
|
padding: 0px;
|
||||||
border: 1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation ul li {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px 6px;
|
padding: 3px 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation ul li.statusError {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul li.actionDetached {
|
||||||
background-color: #ffd3d3;
|
background-color: #ffd0cc;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation ul li.statusUpdate {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul li.actionModified {
|
||||||
background-color: #d3f3ff;
|
background-color: #e2f0fa;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devicesNavigation ul li.statusNew {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul li.actionAdded {
|
||||||
background-color: #d9ffb4;
|
background-color: #e7f9d5;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices {
|
#Devices_Import_Review #Devices_Import_Review_Navigation ul li.actionUnchanged {
|
||||||
border: solid 1px #f4f4f4;
|
|
||||||
border-collapse: collapse;
|
|
||||||
margin-top: 6px;
|
|
||||||
}
|
|
||||||
#deviceImportReview #devices > tbody > tr > td {
|
|
||||||
border: solid 1px #f4f4f4;
|
|
||||||
background-color: #ffffff;
|
|
||||||
}
|
|
||||||
#deviceImportReview #devices > tbody > tr:nth-child(odd) > td {
|
|
||||||
background-color: #fcfcfc;
|
background-color: #fcfcfc;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > thead > tr > th,
|
#Devices_Import_Review #Devices_Import_Review_TableContainer {
|
||||||
#deviceImportReview #devices > tbody > tr > th {
|
margin: 18px 0;
|
||||||
background-color: #f4f4f4;
|
overflow-x: auto;
|
||||||
border: solid 1px #f4f4f4;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody > tr:hover > td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > thead {
|
||||||
background-color: #fefefe;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody > tr:hover:nth-child(odd) > td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > thead tr:nth-child(2) th {
|
||||||
background-color: #fafafa;
|
padding-top: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tfoot > tr > th,
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.action {
|
||||||
#deviceImportReview #devices > tfoot > tr > td {
|
text-align: center;
|
||||||
background-color: #f4f4f4;
|
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionDetached td.action i:before {
|
||||||
vertical-align: middle;
|
color: #e51400;
|
||||||
min-height: 32px;
|
content: "\f12a";
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr.statusError td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionDetached td {
|
||||||
background-color: #ffd3d3;
|
background-color: #ffe7e5;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr.statusUpdate td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionUnchanged td.action i:before {
|
||||||
background-color: #d3f3ff;
|
content: "\f068";
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr.statusNew td {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionUnchanged td {
|
||||||
background-color: #d9ffb4;
|
background-color: #fcfcfc;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr td.action {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionUnchanged td:nth-child(n+3) {
|
||||||
font-weight: bold;
|
color: #cccccc;
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr td.serialNumber {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionModified td.action i:before {
|
||||||
font-family: Consolas, "Courier New", monospace;
|
color: #1e6dab;
|
||||||
font-weight: bold;
|
content: "\f040";
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody tr td.model img.modelImage {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionModified td {
|
||||||
width: 32px;
|
background-color: #f4f9fd;
|
||||||
height: 32px;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
}
|
||||||
#deviceImportReview #devices > tbody .error {
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionAdded td.action i:before {
|
||||||
font-weight: bold;
|
color: #60a917;
|
||||||
|
content: "\f067";
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr.actionAdded td {
|
||||||
|
background-color: #e7f9d5;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody tr:not(.actionUnchanged) td.actionUnchanged:nth-child(n+3):not(.headerDeviceSerialNumber) {
|
||||||
|
color: #cccccc;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.actionError {
|
||||||
|
color: #e51400;
|
||||||
|
background-color: #fff1ef;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.actionError span.errorMessage {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.actionModified {
|
||||||
|
background-color: #e2f0fa !important;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerDeviceSerialNumber,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerDeviceDecommissionedDate,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerDeviceDecommissionedReason,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerModelId,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerBatchId,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerProfileId,
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody td.headerAssignedUserId {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
#Devices_Import_Review #Devices_Import_Review_TableContainer table > tbody span.smallMessage {
|
||||||
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,118 +357,250 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#deviceImport {
|
#Devices_Import {
|
||||||
#ImportFile {
|
#ImportFile {
|
||||||
width: 100%;
|
width: 96%;
|
||||||
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#documentation {
|
#Devices_Import_Documentation {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
margin: 20px auto;
|
margin: 20px auto;
|
||||||
|
|
||||||
& > table {
|
& > table > tbody th:first-child {
|
||||||
& > thead > tr > th:first-child {
|
width: 220px;
|
||||||
width: 100px;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Devices_Import_Completed_Dialog {
|
||||||
|
padding: 50px 0;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: @StatusSuccess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Devices_Import_Loading_Dialog {
|
||||||
|
padding-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
i {
|
||||||
|
margin-right: 10px;
|
||||||
|
color: @StatusInformation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Devices_Import_Headers {
|
||||||
|
|
||||||
|
#Devices_Import_Headers_TableContainer {
|
||||||
|
margin: 18px 0;
|
||||||
|
overflow-x: auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
|
||||||
|
table {
|
||||||
|
& > thead {
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
ul.importHeaderType {
|
||||||
|
& > li > a > span:not(.ui-menu-icon) {
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td.headerIgnoreColumn {
|
||||||
|
background-color: @StatusAlert;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:not(.headerIgnoreColumn) {
|
||||||
|
background-color: @StatusInformation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& > tbody {
|
||||||
|
td.headerDeviceSerialNumber {
|
||||||
|
border-top-color: lighten(@StatusInformation, 50%);
|
||||||
|
border-bottom-color: lighten(@StatusInformation, 50%);
|
||||||
|
background-color: lighten(@StatusInformation, 54%);
|
||||||
|
}
|
||||||
|
|
||||||
|
td.headerIgnoreColumn {
|
||||||
|
max-width: 150px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
-ms-text-overflow: ellipsis;
|
||||||
|
-o-text-overflow: ellipsis;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: @SubtleBorderColour;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#deviceImportReview {
|
#Devices_Import_Parsing_Dialog {
|
||||||
|
padding-top: 50px;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
#errorMessage {
|
i {
|
||||||
font-weight: bold;
|
margin-right: 10px;
|
||||||
color: red;
|
color: @StatusInformation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#devicesNavigation {
|
// Icons used within Devices_Import_Review
|
||||||
|
@import "FontAwesome\variables.less";
|
||||||
|
|
||||||
|
#Devices_Import_Review {
|
||||||
|
|
||||||
|
#Devices_Import_Review_Navigation {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px;
|
padding: 0px;
|
||||||
border: 1px solid #bbb;
|
border: 1px solid #bbb;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 1px 6px;
|
padding: 3px 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
|
||||||
&.statusError {
|
&.actionDetached {
|
||||||
background-color: #ffd3d3;
|
background-color: lighten(@StatusError, 45%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.statusUpdate {
|
&.actionModified {
|
||||||
background-color: #d3f3ff;
|
background-color: lighten(@StatusInformation, 54%);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.statusNew {
|
&.actionAdded {
|
||||||
background-color: #d9ffb4;
|
background-color: lighten(@StatusSuccess, 53%);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.actionUnchanged {
|
||||||
|
background-color: @TableDataRowBackgroundColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#devices {
|
#Devices_Import_Review_TableContainer {
|
||||||
.tableData;
|
margin: 18px 0;
|
||||||
margin-top: 6px;
|
overflow-x: auto;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
|
||||||
|
table {
|
||||||
|
& > thead {
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
tr:nth-child(2) th {
|
||||||
|
padding-top: 0;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
& > tbody {
|
& > tbody {
|
||||||
|
|
||||||
td {
|
|
||||||
vertical-align: middle;
|
|
||||||
min-height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.statusError td {
|
|
||||||
background-color: #ffd3d3;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.statusUpdate td {
|
|
||||||
background-color: #d3f3ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr.statusNew td {
|
|
||||||
background-color: #d9ffb4;
|
|
||||||
}
|
|
||||||
|
|
||||||
tr {
|
|
||||||
td.action {
|
td.action {
|
||||||
font-weight: bold;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
td.serialNumber {
|
tr.actionDetached {
|
||||||
font-family: @FontFamilyMono;
|
td.action {
|
||||||
font-weight: bold;
|
i:before {
|
||||||
}
|
color: @StatusError;
|
||||||
|
content: @fa-var-exclamation;
|
||||||
td.model {
|
|
||||||
img.modelImage {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td.profile {
|
td {
|
||||||
}
|
background-color: lighten(@StatusError, 50%);
|
||||||
|
|
||||||
td.batch {
|
|
||||||
}
|
|
||||||
|
|
||||||
td.assignedUser {
|
|
||||||
}
|
|
||||||
|
|
||||||
td.location {
|
|
||||||
}
|
|
||||||
|
|
||||||
td.assetNumber {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.error {
|
tr.actionUnchanged {
|
||||||
font-weight: bold;
|
td.action {
|
||||||
|
i:before {
|
||||||
|
content: @fa-var-minus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
background-color: @TableDataRowBackgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:nth-child(n+3) {
|
||||||
|
color: @SubtleBorderColour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.actionModified {
|
||||||
|
td.action {
|
||||||
|
i:before {
|
||||||
|
color: @StatusInformation;
|
||||||
|
content: @fa-var-pencil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
background-color: lighten(@StatusInformation, 58%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.actionAdded {
|
||||||
|
td.action {
|
||||||
|
i:before {
|
||||||
|
color: @StatusSuccess;
|
||||||
|
content: @fa-var-plus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
background-color: lighten(@StatusSuccess, 53%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tr:not(.actionUnchanged) {
|
||||||
|
td.actionUnchanged:nth-child(n+3):not(.headerDeviceSerialNumber) {
|
||||||
|
color: @SubtleBorderColour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td.actionError {
|
||||||
|
color: @StatusError;
|
||||||
|
background-color: lighten(@StatusError, 52%);
|
||||||
|
|
||||||
|
span.errorMessage {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
td.actionModified {
|
||||||
|
background-color: lighten(@StatusInformation, 54%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.headerDeviceSerialNumber, td.headerDeviceDecommissionedDate, td.headerDeviceDecommissionedReason,
|
||||||
|
td.headerModelId, td.headerBatchId, td.headerProfileId,
|
||||||
|
td.headerAssignedUserId {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.smallMessage {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+1499
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -274,3 +274,8 @@ input:-moz-placeholder {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
padding: .6em 1em;
|
padding: .6em 1em;
|
||||||
}
|
}
|
||||||
|
body .ui-tooltip {
|
||||||
|
border-width: 1px;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|||||||
@@ -158,10 +158,8 @@ input:-moz-placeholder {
|
|||||||
.ui-dialog {
|
.ui-dialog {
|
||||||
animation-name: ui-dialog-show;
|
animation-name: ui-dialog-show;
|
||||||
-webkit-animation-name: ui-dialog-show;
|
-webkit-animation-name: ui-dialog-show;
|
||||||
|
|
||||||
animation-duration: .2s;
|
animation-duration: .2s;
|
||||||
-webkit-animation-duration: .2s;
|
-webkit-animation-duration: .2s;
|
||||||
|
|
||||||
animation-timing-function: ease-in-out;
|
animation-timing-function: ease-in-out;
|
||||||
-webkit-animation-timing-function: ease-in-out;
|
-webkit-animation-timing-function: ease-in-out;
|
||||||
}
|
}
|
||||||
@@ -171,6 +169,7 @@ input:-moz-placeholder {
|
|||||||
transform: translateY(-30px);
|
transform: translateY(-30px);
|
||||||
opacity: 0.0;
|
opacity: 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
transform: translateY(0);
|
transform: translateY(0);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -182,6 +181,7 @@ input:-moz-placeholder {
|
|||||||
-webkit-transform: translateY(-30px);
|
-webkit-transform: translateY(-30px);
|
||||||
opacity: 0.0;
|
opacity: 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
-webkit-transform: translateY(0);
|
-webkit-transform: translateY(0);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
@@ -191,10 +191,8 @@ input:-moz-placeholder {
|
|||||||
.ui-widget-overlay.ui-front {
|
.ui-widget-overlay.ui-front {
|
||||||
animation-name: ui-dialog-fadeIn;
|
animation-name: ui-dialog-fadeIn;
|
||||||
-webkit-animation-name: ui-dialog-fadeIn;
|
-webkit-animation-name: ui-dialog-fadeIn;
|
||||||
|
|
||||||
animation-duration: .2s;
|
animation-duration: .2s;
|
||||||
-webkit-animation-duration: .2s;
|
-webkit-animation-duration: .2s;
|
||||||
|
|
||||||
animation-timing-function: ease-in-out;
|
animation-timing-function: ease-in-out;
|
||||||
-webkit-animation-timing-function: ease-in-out;
|
-webkit-animation-timing-function: ease-in-out;
|
||||||
}
|
}
|
||||||
@@ -203,6 +201,7 @@ input:-moz-placeholder {
|
|||||||
0% {
|
0% {
|
||||||
opacity: 0.0;
|
opacity: 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -212,6 +211,7 @@ input:-moz-placeholder {
|
|||||||
0% {
|
0% {
|
||||||
opacity: 0.0;
|
opacity: 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
100% {
|
100% {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
@@ -243,3 +243,10 @@ input:-moz-placeholder {
|
|||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
padding: .6em 1em;
|
padding: .6em 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tooltip
|
||||||
|
body .ui-tooltip {
|
||||||
|
border-width: 1px;
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
@@ -124,36 +124,67 @@ namespace Disco.Web.Controllers
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Import/Export
|
#region Import
|
||||||
[DiscoAuthorizeAny(Claims.Device.Actions.Import, Claims.Device.Actions.Export), HttpGet]
|
[DiscoAuthorize(Claims.Device.Actions.Import), HttpGet]
|
||||||
public virtual ActionResult ImportExport()
|
public virtual ActionResult Import(string Id)
|
||||||
{
|
{
|
||||||
Models.Device.ImportModel m = new Models.Device.ImportModel();
|
var m = new Models.Device.ImportModel()
|
||||||
|
{
|
||||||
|
DeviceModels = Database.DeviceModels.ToList(),
|
||||||
|
DeviceProfiles = Database.DeviceProfiles.ToList(),
|
||||||
|
DeviceBatches = Database.DeviceBatches.ToList()
|
||||||
|
};
|
||||||
|
|
||||||
if (Authorization.Has(Claims.Device.Actions.Import))
|
if (!string.IsNullOrWhiteSpace(Id))
|
||||||
{
|
m.CompletedImportSessionContext = Areas.API.Controllers.DeviceController.Import_RetrieveContext(Id, Remove: true);
|
||||||
m.DeviceModels = Database.DeviceModels.ToList();
|
|
||||||
m.DeviceProfiles = Database.DeviceProfiles.ToList();
|
|
||||||
m.DeviceBatches = Database.DeviceBatches.ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI Extensions
|
// UI Extensions
|
||||||
UIExtensions.ExecuteExtensions<DeviceImportModel>(this.ControllerContext, m);
|
UIExtensions.ExecuteExtensions<DeviceImportModel>(this.ControllerContext, m);
|
||||||
|
|
||||||
return View(m);
|
return View(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
[DiscoAuthorize(Claims.Device.Actions.Import), HttpGet]
|
[DiscoAuthorize(Claims.Device.Actions.Import), HttpGet]
|
||||||
public virtual ActionResult ImportReview(string ImportParseTaskId)
|
public virtual ActionResult ImportHeaders(string Id)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(ImportParseTaskId))
|
if (string.IsNullOrWhiteSpace(Id))
|
||||||
throw new ArgumentNullException("ImportParseTaskId");
|
throw new ArgumentNullException("Id");
|
||||||
|
|
||||||
var session = Disco.BI.DeviceBI.Importing.Import.GetSession(ImportParseTaskId);
|
var context = Areas.API.Controllers.DeviceController.Import_RetrieveContext(Id);
|
||||||
|
|
||||||
if (session == null)
|
if (context == null)
|
||||||
throw new ArgumentException("The Import Parse Task Id is invalid or the session timed out (60 minutes), try importing again", "ImportParseTaskId");
|
throw new ArgumentException("The Import Session Id is invalid or the session timed out (60 minutes), try importing again", "Id");
|
||||||
|
|
||||||
Models.Device.ImportReviewModel m = Models.Device.ImportReviewModel.FromImportDeviceSession(session);
|
var m = new Models.Device.ImportHeadersModel()
|
||||||
|
{
|
||||||
|
Context = context
|
||||||
|
};
|
||||||
|
|
||||||
|
// UI Extensions
|
||||||
|
UIExtensions.ExecuteExtensions<DeviceImportHeadersModel>(this.ControllerContext, m);
|
||||||
|
|
||||||
|
return View(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DiscoAuthorize(Claims.Device.Actions.Import), HttpGet]
|
||||||
|
public virtual ActionResult ImportReview(string Id)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(Id))
|
||||||
|
throw new ArgumentNullException("Id");
|
||||||
|
|
||||||
|
var context = Areas.API.Controllers.DeviceController.Import_RetrieveContext(Id);
|
||||||
|
|
||||||
|
if (context == null)
|
||||||
|
throw new ArgumentException("The Import Session Id is invalid or the session timed out (60 minutes), try importing again", "Id");
|
||||||
|
|
||||||
|
var m = new Models.Device.ImportReviewModel()
|
||||||
|
{
|
||||||
|
Context = context,
|
||||||
|
StatisticErrorRecords = context.Records.Count(r => r.HasError),
|
||||||
|
StatisticNewRecords = context.Records.Count(r => r.RecordAction == System.Data.EntityState.Added),
|
||||||
|
StatisticModifiedRecords = context.Records.Count(r => r.RecordAction == System.Data.EntityState.Modified),
|
||||||
|
StatisticUnmodifiedRecords = context.Records.Count(r => r.RecordAction == System.Data.EntityState.Unchanged)
|
||||||
|
};
|
||||||
|
|
||||||
// UI Extensions
|
// UI Extensions
|
||||||
UIExtensions.ExecuteExtensions<DeviceImportReviewModel>(this.ControllerContext, m);
|
UIExtensions.ExecuteExtensions<DeviceImportReviewModel>(this.ControllerContext, m);
|
||||||
|
|||||||
@@ -545,7 +545,13 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Extensions\T4MVCExtensions.cs" />
|
<Compile Include="Extensions\T4MVCExtensions.cs" />
|
||||||
<Compile Include="Models\Device\ExportModel.cs" />
|
<Compile Include="Models\Device\ExportModel.cs" />
|
||||||
|
<Compile Include="Models\Device\ImportHeadersModel.cs" />
|
||||||
<Compile Include="Models\InitialConfig\AdministratorsModel.cs" />
|
<Compile Include="Models\InitialConfig\AdministratorsModel.cs" />
|
||||||
|
<Compile Include="Views\Device\ImportHeaders.generated.cs">
|
||||||
|
<DependentUpon>ImportHeaders.cshtml</DependentUpon>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\Device\Export.generated.cs">
|
<Compile Include="Views\Device\Export.generated.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
@@ -663,10 +669,10 @@
|
|||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<DependentUpon>_Subject.cshtml</DependentUpon>
|
<DependentUpon>_Subject.cshtml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\Device\ImportExport.generated.cs">
|
<Compile Include="Views\Device\Import.generated.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<DependentUpon>ImportExport.cshtml</DependentUpon>
|
<DependentUpon>Import.cshtml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\Device\ImportReview.generated.cs">
|
<Compile Include="Views\Device\ImportReview.generated.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
@@ -1253,6 +1259,18 @@
|
|||||||
<DependentUpon>ExpressionEditor.css</DependentUpon>
|
<DependentUpon>ExpressionEditor.css</DependentUpon>
|
||||||
</Content>
|
</Content>
|
||||||
<None Include="ClientSource\Style\Fancytree\disco.fancytree.less" />
|
<None Include="ClientSource\Style\Fancytree\disco.fancytree.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\bordered-pulled.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\core.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\fixed-width.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\icons.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\larger.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\list.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\mixins.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\path.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\rotated-flipped.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\spinning.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\stacked.less" />
|
||||||
|
<None Include="ClientSource\Style\FontAwesome\variables.less" />
|
||||||
<None Include="ClientSource\Style\Images\Actions\dataTableFirst.png" />
|
<None Include="ClientSource\Style\Images\Actions\dataTableFirst.png" />
|
||||||
<None Include="ClientSource\Style\Images\Actions\dataTableFirstDisabled.png" />
|
<None Include="ClientSource\Style\Images\Actions\dataTableFirstDisabled.png" />
|
||||||
<None Include="ClientSource\Style\Images\Actions\dataTableLast.png" />
|
<None Include="ClientSource\Style\Images\Actions\dataTableLast.png" />
|
||||||
@@ -1347,6 +1365,12 @@
|
|||||||
<None Include="ClientSource\Style\normalize.min.css">
|
<None Include="ClientSource\Style\normalize.min.css">
|
||||||
<DependentUpon>normalize.less</DependentUpon>
|
<DependentUpon>normalize.less</DependentUpon>
|
||||||
</None>
|
</None>
|
||||||
|
<Content Include="ClientSource\Style\jQueryUI\jquery-ui.css">
|
||||||
|
<DependentUpon>jquery-ui.less</DependentUpon>
|
||||||
|
</Content>
|
||||||
|
<Content Include="ClientSource\Style\jQueryUI\jquery-ui.min.css">
|
||||||
|
<DependentUpon>jquery-ui.less</DependentUpon>
|
||||||
|
</Content>
|
||||||
<Content Include="ClientSource\Style\Public\HeldDevices.css">
|
<Content Include="ClientSource\Style\Public\HeldDevices.css">
|
||||||
<DependentUpon>HeldDevices.less</DependentUpon>
|
<DependentUpon>HeldDevices.less</DependentUpon>
|
||||||
</Content>
|
</Content>
|
||||||
@@ -1526,6 +1550,10 @@
|
|||||||
<Generator>RazorGenerator</Generator>
|
<Generator>RazorGenerator</Generator>
|
||||||
<LastGenOutput>AddOffline.generated.cs</LastGenOutput>
|
<LastGenOutput>AddOffline.generated.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
|
<None Include="Views\Device\ImportHeaders.cshtml">
|
||||||
|
<Generator>RazorGenerator</Generator>
|
||||||
|
<LastGenOutput>ImportHeaders.generated.cs</LastGenOutput>
|
||||||
|
</None>
|
||||||
<None Include="Views\Device\DeviceParts\_Details.cshtml">
|
<None Include="Views\Device\DeviceParts\_Details.cshtml">
|
||||||
<Generator>RazorGenerator</Generator>
|
<Generator>RazorGenerator</Generator>
|
||||||
<LastGenOutput>_Details.generated.cs</LastGenOutput>
|
<LastGenOutput>_Details.generated.cs</LastGenOutput>
|
||||||
@@ -1554,9 +1582,9 @@
|
|||||||
<Generator>RazorGenerator</Generator>
|
<Generator>RazorGenerator</Generator>
|
||||||
<LastGenOutput>Export.generated.cs</LastGenOutput>
|
<LastGenOutput>Export.generated.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
<None Include="Views\Device\ImportExport.cshtml">
|
<None Include="Views\Device\Import.cshtml">
|
||||||
<Generator>RazorGenerator</Generator>
|
<Generator>RazorGenerator</Generator>
|
||||||
<LastGenOutput>ImportExport.generated.cs</LastGenOutput>
|
<LastGenOutput>Import.generated.cs</LastGenOutput>
|
||||||
</None>
|
</None>
|
||||||
<None Include="Views\Device\ImportReview.cshtml">
|
<None Include="Views\Device\ImportReview.cshtml">
|
||||||
<Generator>RazorGenerator</Generator>
|
<Generator>RazorGenerator</Generator>
|
||||||
@@ -2063,7 +2091,7 @@
|
|||||||
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
<SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile>
|
||||||
</WebProjectProperties>
|
</WebProjectProperties>
|
||||||
</FlavorProperties>
|
</FlavorProperties>
|
||||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
|
||||||
</VisualStudio>
|
</VisualStudio>
|
||||||
</ProjectExtensions>
|
</ProjectExtensions>
|
||||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
using Disco.Models.UI.Device;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Disco.Web.Models.Device
|
||||||
|
{
|
||||||
|
public class ImportHeadersModel : DeviceImportHeadersModel
|
||||||
|
{
|
||||||
|
public IDeviceImportContext Context { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<Tuple<DeviceImportFieldTypes, string>> HeaderTypes { get; set; }
|
||||||
|
|
||||||
|
public ImportHeadersModel()
|
||||||
|
{
|
||||||
|
HeaderTypes = typeof(DeviceImportFieldTypes)
|
||||||
|
.GetFields()
|
||||||
|
.Select(p => Tuple.Create(p, (DisplayAttribute)p.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault()))
|
||||||
|
.Where(p => p.Item2 != null)
|
||||||
|
.Select(p => Tuple.Create((DeviceImportFieldTypes)p.Item1.GetRawConstantValue(), p.Item2.Name)).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Disco.Models.Repository;
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
using Disco.Models.UI.Device;
|
using Disco.Models.UI.Device;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -13,8 +14,26 @@ namespace Disco.Web.Models.Device
|
|||||||
[Required, Display(Name = "CSV Import File")]
|
[Required, Display(Name = "CSV Import File")]
|
||||||
public HttpPostedFileBase ImportFile { get; set; }
|
public HttpPostedFileBase ImportFile { get; set; }
|
||||||
|
|
||||||
|
[Required, Display(Name = "Has Header")]
|
||||||
|
public bool HasHeader { get; set; }
|
||||||
|
|
||||||
|
public IDeviceImportContext CompletedImportSessionContext { get; set; }
|
||||||
|
|
||||||
public List<DeviceModel> DeviceModels { get; set; }
|
public List<DeviceModel> DeviceModels { get; set; }
|
||||||
public List<DeviceProfile> DeviceProfiles { get; set; }
|
public List<DeviceProfile> DeviceProfiles { get; set; }
|
||||||
public List<DeviceBatch> DeviceBatches { get; set; }
|
public List<DeviceBatch> DeviceBatches { get; set; }
|
||||||
|
|
||||||
|
public IEnumerable<Tuple<string, string, string>> HeaderTypes { get; set; }
|
||||||
|
|
||||||
|
public ImportModel()
|
||||||
|
{
|
||||||
|
HasHeader = true;
|
||||||
|
|
||||||
|
HeaderTypes = typeof(DeviceImportFieldTypes)
|
||||||
|
.GetFields()
|
||||||
|
.Select(p => Tuple.Create(p, (DisplayAttribute)p.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault()))
|
||||||
|
.Where(p => p.Item2 != null && p.Item1.Name != DeviceImportFieldTypes.IgnoreColumn.ToString())
|
||||||
|
.Select(p => Tuple.Create(p.Item1.Name, p.Item2.Name, p.Item2.Description)).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,26 +1,35 @@
|
|||||||
using Disco.Models.BI.Device;
|
using Disco.Models.Services.Devices.Importing;
|
||||||
using Disco.Models.UI.Device;
|
using Disco.Models.UI.Device;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Web;
|
|
||||||
|
|
||||||
namespace Disco.Web.Models.Device
|
namespace Disco.Web.Models.Device
|
||||||
{
|
{
|
||||||
public class ImportReviewModel : DeviceImportReviewModel
|
public class ImportReviewModel : DeviceImportReviewModel
|
||||||
{
|
{
|
||||||
public string ImportParseTaskId { get; set; }
|
public IDeviceImportContext Context { get; set; }
|
||||||
public string ImportFilename { get; set; }
|
|
||||||
public List<ImportDevice> ImportDevices { get; set; }
|
|
||||||
|
|
||||||
public static ImportReviewModel FromImportDeviceSession(ImportDeviceSession session)
|
public int StatisticErrorRecords { get; set; }
|
||||||
|
public int StatisticNewRecords { get; set; }
|
||||||
|
public int StatisticModifiedRecords { get; set; }
|
||||||
|
public int StatisticUnmodifiedRecords { get; set; }
|
||||||
|
|
||||||
|
public int StatisticImportRecords
|
||||||
{
|
{
|
||||||
return new ImportReviewModel()
|
get { return this.StatisticNewRecords + StatisticModifiedRecords; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<Tuple<DeviceImportFieldTypes, string>> HeaderTypes { get; set; }
|
||||||
|
|
||||||
|
public ImportReviewModel()
|
||||||
{
|
{
|
||||||
ImportParseTaskId = session.ImportParseTaskId,
|
HeaderTypes = typeof(DeviceImportFieldTypes)
|
||||||
ImportFilename = session.ImportFilename,
|
.GetFields()
|
||||||
ImportDevices = session.ImportDevices
|
.Select(p => Tuple.Create(p, (DisplayAttribute)p.GetCustomAttributes(typeof(DisplayAttribute), false).FirstOrDefault()))
|
||||||
};
|
.Where(p => p.Item2 != null)
|
||||||
|
.Select(p => Tuple.Create((DeviceImportFieldTypes)p.Item1.GetRawConstantValue(), p.Item2.Name)).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+119
-31
@@ -558,12 +558,24 @@ namespace Links
|
|||||||
private const string URLPATH = "~/ClientSource/Style/FontAwesome";
|
private const string URLPATH = "~/ClientSource/Style/FontAwesome";
|
||||||
public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
|
public static string Url() { return T4MVCHelpers.ProcessVirtualPath(URLPATH); }
|
||||||
public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
|
public static string Url(string fileName) { return T4MVCHelpers.ProcessVirtualPath(URLPATH + "/" + fileName); }
|
||||||
|
public static readonly string bordered_pulled_less = Url("bordered-pulled.less");
|
||||||
|
public static readonly string core_less = Url("core.less");
|
||||||
|
public static readonly string fixed_width_less = Url("fixed-width.less");
|
||||||
public static readonly string font_awesome_less = Url("font-awesome.less");
|
public static readonly string font_awesome_less = Url("font-awesome.less");
|
||||||
public static readonly string fontawesome_webfont_eot = Url("fontawesome-webfont.eot");
|
public static readonly string fontawesome_webfont_eot = Url("fontawesome-webfont.eot");
|
||||||
public static readonly string fontawesome_webfont_svg = Url("fontawesome-webfont.svg");
|
public static readonly string fontawesome_webfont_svg = Url("fontawesome-webfont.svg");
|
||||||
public static readonly string fontawesome_webfont_ttf = Url("fontawesome-webfont.ttf");
|
public static readonly string fontawesome_webfont_ttf = Url("fontawesome-webfont.ttf");
|
||||||
public static readonly string fontawesome_webfont_woff = Url("fontawesome-webfont.woff");
|
public static readonly string fontawesome_webfont_woff = Url("fontawesome-webfont.woff");
|
||||||
public static readonly string FontAwesome_otf = Url("FontAwesome.otf");
|
public static readonly string FontAwesome_otf = Url("FontAwesome.otf");
|
||||||
|
public static readonly string icons_less = Url("icons.less");
|
||||||
|
public static readonly string larger_less = Url("larger.less");
|
||||||
|
public static readonly string list_less = Url("list.less");
|
||||||
|
public static readonly string mixins_less = Url("mixins.less");
|
||||||
|
public static readonly string path_less = Url("path.less");
|
||||||
|
public static readonly string rotated_flipped_less = Url("rotated-flipped.less");
|
||||||
|
public static readonly string spinning_less = Url("spinning.less");
|
||||||
|
public static readonly string stacked_less = Url("stacked.less");
|
||||||
|
public static readonly string variables_less = Url("variables.less");
|
||||||
}
|
}
|
||||||
|
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
@@ -683,6 +695,9 @@ namespace Links
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static readonly string jquery_ui_less = Url("jquery-ui.less");
|
public static readonly string jquery_ui_less = Url("jquery-ui.less");
|
||||||
|
public static readonly string jquery_ui_css = T4MVCHelpers.IsProduction() && T4Extensions.FileExists(URLPATH + "/jquery-ui.min.css") ? Url("jquery-ui.min.css") : Url("jquery-ui.css");
|
||||||
|
|
||||||
|
public static readonly string jquery_ui_min_css = Url("jquery-ui.min.css");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly string jQueryUIExtensions_less = Url("jQueryUIExtensions.less");
|
public static readonly string jQueryUIExtensions_less = Url("jQueryUIExtensions.less");
|
||||||
@@ -889,6 +904,18 @@ namespace Disco.Web.Controllers
|
|||||||
}
|
}
|
||||||
[NonAction]
|
[NonAction]
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public virtual System.Web.Mvc.ActionResult Import()
|
||||||
|
{
|
||||||
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Import);
|
||||||
|
}
|
||||||
|
[NonAction]
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public virtual System.Web.Mvc.ActionResult ImportHeaders()
|
||||||
|
{
|
||||||
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportHeaders);
|
||||||
|
}
|
||||||
|
[NonAction]
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public virtual System.Web.Mvc.ActionResult ImportReview()
|
public virtual System.Web.Mvc.ActionResult ImportReview()
|
||||||
{
|
{
|
||||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportReview);
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportReview);
|
||||||
@@ -918,7 +945,8 @@ namespace Disco.Web.Controllers
|
|||||||
public readonly string Index = "Index";
|
public readonly string Index = "Index";
|
||||||
public readonly string AddOffline = "AddOffline";
|
public readonly string AddOffline = "AddOffline";
|
||||||
public readonly string Export = "Export";
|
public readonly string Export = "Export";
|
||||||
public readonly string ImportExport = "ImportExport";
|
public readonly string Import = "Import";
|
||||||
|
public readonly string ImportHeaders = "ImportHeaders";
|
||||||
public readonly string ImportReview = "ImportReview";
|
public readonly string ImportReview = "ImportReview";
|
||||||
public readonly string Show = "Show";
|
public readonly string Show = "Show";
|
||||||
}
|
}
|
||||||
@@ -929,7 +957,8 @@ namespace Disco.Web.Controllers
|
|||||||
public const string Index = "Index";
|
public const string Index = "Index";
|
||||||
public const string AddOffline = "AddOffline";
|
public const string AddOffline = "AddOffline";
|
||||||
public const string Export = "Export";
|
public const string Export = "Export";
|
||||||
public const string ImportExport = "ImportExport";
|
public const string Import = "Import";
|
||||||
|
public const string ImportHeaders = "ImportHeaders";
|
||||||
public const string ImportReview = "ImportReview";
|
public const string ImportReview = "ImportReview";
|
||||||
public const string Show = "Show";
|
public const string Show = "Show";
|
||||||
}
|
}
|
||||||
@@ -953,13 +982,29 @@ namespace Disco.Web.Controllers
|
|||||||
public readonly string ExportType = "ExportType";
|
public readonly string ExportType = "ExportType";
|
||||||
public readonly string ExportTypeTargetId = "ExportTypeTargetId";
|
public readonly string ExportTypeTargetId = "ExportTypeTargetId";
|
||||||
}
|
}
|
||||||
|
static readonly ActionParamsClass_Import s_params_Import = new ActionParamsClass_Import();
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public ActionParamsClass_Import ImportParams { get { return s_params_Import; } }
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public class ActionParamsClass_Import
|
||||||
|
{
|
||||||
|
public readonly string Id = "Id";
|
||||||
|
}
|
||||||
|
static readonly ActionParamsClass_ImportHeaders s_params_ImportHeaders = new ActionParamsClass_ImportHeaders();
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public ActionParamsClass_ImportHeaders ImportHeadersParams { get { return s_params_ImportHeaders; } }
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public class ActionParamsClass_ImportHeaders
|
||||||
|
{
|
||||||
|
public readonly string Id = "Id";
|
||||||
|
}
|
||||||
static readonly ActionParamsClass_ImportReview s_params_ImportReview = new ActionParamsClass_ImportReview();
|
static readonly ActionParamsClass_ImportReview s_params_ImportReview = new ActionParamsClass_ImportReview();
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public ActionParamsClass_ImportReview ImportReviewParams { get { return s_params_ImportReview; } }
|
public ActionParamsClass_ImportReview ImportReviewParams { get { return s_params_ImportReview; } }
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public class ActionParamsClass_ImportReview
|
public class ActionParamsClass_ImportReview
|
||||||
{
|
{
|
||||||
public readonly string ImportParseTaskId = "ImportParseTaskId";
|
public readonly string Id = "Id";
|
||||||
}
|
}
|
||||||
static readonly ActionParamsClass_Show s_params_Show = new ActionParamsClass_Show();
|
static readonly ActionParamsClass_Show s_params_Show = new ActionParamsClass_Show();
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
@@ -983,7 +1028,8 @@ namespace Disco.Web.Controllers
|
|||||||
public readonly string _ViewStart = "_ViewStart";
|
public readonly string _ViewStart = "_ViewStart";
|
||||||
public readonly string AddOffline = "AddOffline";
|
public readonly string AddOffline = "AddOffline";
|
||||||
public readonly string Export = "Export";
|
public readonly string Export = "Export";
|
||||||
public readonly string ImportExport = "ImportExport";
|
public readonly string Import = "Import";
|
||||||
|
public readonly string ImportHeaders = "ImportHeaders";
|
||||||
public readonly string ImportReview = "ImportReview";
|
public readonly string ImportReview = "ImportReview";
|
||||||
public readonly string Index = "Index";
|
public readonly string Index = "Index";
|
||||||
public readonly string Show = "Show";
|
public readonly string Show = "Show";
|
||||||
@@ -992,7 +1038,8 @@ namespace Disco.Web.Controllers
|
|||||||
public readonly string _ViewStart = "~/Views/Device/_ViewStart.cshtml";
|
public readonly string _ViewStart = "~/Views/Device/_ViewStart.cshtml";
|
||||||
public readonly string AddOffline = "~/Views/Device/AddOffline.cshtml";
|
public readonly string AddOffline = "~/Views/Device/AddOffline.cshtml";
|
||||||
public readonly string Export = "~/Views/Device/Export.cshtml";
|
public readonly string Export = "~/Views/Device/Export.cshtml";
|
||||||
public readonly string ImportExport = "~/Views/Device/ImportExport.cshtml";
|
public readonly string Import = "~/Views/Device/Import.cshtml";
|
||||||
|
public readonly string ImportHeaders = "~/Views/Device/ImportHeaders.cshtml";
|
||||||
public readonly string ImportReview = "~/Views/Device/ImportReview.cshtml";
|
public readonly string ImportReview = "~/Views/Device/ImportReview.cshtml";
|
||||||
public readonly string Index = "~/Views/Device/Index.cshtml";
|
public readonly string Index = "~/Views/Device/Index.cshtml";
|
||||||
public readonly string Show = "~/Views/Device/Show.cshtml";
|
public readonly string Show = "~/Views/Device/Show.cshtml";
|
||||||
@@ -1067,22 +1114,33 @@ namespace Disco.Web.Controllers
|
|||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void ImportExportOverride(T4MVC_System_Web_Mvc_ActionResult callInfo);
|
partial void ImportOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||||
|
|
||||||
public override System.Web.Mvc.ActionResult ImportExport()
|
public override System.Web.Mvc.ActionResult Import(string Id)
|
||||||
{
|
{
|
||||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportExport);
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Import);
|
||||||
ImportExportOverride(callInfo);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||||
|
ImportOverride(callInfo, Id);
|
||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void ImportReviewOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string ImportParseTaskId);
|
partial void ImportHeadersOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||||
|
|
||||||
public override System.Web.Mvc.ActionResult ImportReview(string ImportParseTaskId)
|
public override System.Web.Mvc.ActionResult ImportHeaders(string Id)
|
||||||
|
{
|
||||||
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportHeaders);
|
||||||
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||||
|
ImportHeadersOverride(callInfo, Id);
|
||||||
|
return callInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void ImportReviewOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||||
|
|
||||||
|
public override System.Web.Mvc.ActionResult ImportReview(string Id)
|
||||||
{
|
{
|
||||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportReview);
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportReview);
|
||||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ImportParseTaskId", ImportParseTaskId);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||||
ImportReviewOverride(callInfo, ImportParseTaskId);
|
ImportReviewOverride(callInfo, Id);
|
||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3551,15 +3609,21 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
}
|
}
|
||||||
[NonAction]
|
[NonAction]
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public virtual System.Web.Mvc.ActionResult ImportBegin()
|
||||||
|
{
|
||||||
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportBegin);
|
||||||
|
}
|
||||||
|
[NonAction]
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public virtual System.Web.Mvc.ActionResult ImportParse()
|
public virtual System.Web.Mvc.ActionResult ImportParse()
|
||||||
{
|
{
|
||||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportParse);
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportParse);
|
||||||
}
|
}
|
||||||
[NonAction]
|
[NonAction]
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public virtual System.Web.Mvc.ActionResult ImportProcess()
|
public virtual System.Web.Mvc.ActionResult ImportApply()
|
||||||
{
|
{
|
||||||
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportProcess);
|
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportApply);
|
||||||
}
|
}
|
||||||
[NonAction]
|
[NonAction]
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
@@ -3608,8 +3672,9 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
public readonly string Attachment = "Attachment";
|
public readonly string Attachment = "Attachment";
|
||||||
public readonly string Attachments = "Attachments";
|
public readonly string Attachments = "Attachments";
|
||||||
public readonly string AttachmentRemove = "AttachmentRemove";
|
public readonly string AttachmentRemove = "AttachmentRemove";
|
||||||
|
public readonly string ImportBegin = "ImportBegin";
|
||||||
public readonly string ImportParse = "ImportParse";
|
public readonly string ImportParse = "ImportParse";
|
||||||
public readonly string ImportProcess = "ImportProcess";
|
public readonly string ImportApply = "ImportApply";
|
||||||
public readonly string Export = "Export";
|
public readonly string Export = "Export";
|
||||||
public readonly string ExportRetrieve = "ExportRetrieve";
|
public readonly string ExportRetrieve = "ExportRetrieve";
|
||||||
public readonly string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
|
public readonly string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
|
||||||
@@ -3637,8 +3702,9 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
public const string Attachment = "Attachment";
|
public const string Attachment = "Attachment";
|
||||||
public const string Attachments = "Attachments";
|
public const string Attachments = "Attachments";
|
||||||
public const string AttachmentRemove = "AttachmentRemove";
|
public const string AttachmentRemove = "AttachmentRemove";
|
||||||
|
public const string ImportBegin = "ImportBegin";
|
||||||
public const string ImportParse = "ImportParse";
|
public const string ImportParse = "ImportParse";
|
||||||
public const string ImportProcess = "ImportProcess";
|
public const string ImportApply = "ImportApply";
|
||||||
public const string Export = "Export";
|
public const string Export = "Export";
|
||||||
public const string ExportRetrieve = "ExportRetrieve";
|
public const string ExportRetrieve = "ExportRetrieve";
|
||||||
public const string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
|
public const string MigrateDeviceMacAddressesFromLog = "MigrateDeviceMacAddressesFromLog";
|
||||||
@@ -3821,21 +3887,31 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
{
|
{
|
||||||
public readonly string id = "id";
|
public readonly string id = "id";
|
||||||
}
|
}
|
||||||
|
static readonly ActionParamsClass_ImportBegin s_params_ImportBegin = new ActionParamsClass_ImportBegin();
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public ActionParamsClass_ImportBegin ImportBeginParams { get { return s_params_ImportBegin; } }
|
||||||
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
|
public class ActionParamsClass_ImportBegin
|
||||||
|
{
|
||||||
|
public readonly string ImportFile = "ImportFile";
|
||||||
|
public readonly string HasHeader = "HasHeader";
|
||||||
|
}
|
||||||
static readonly ActionParamsClass_ImportParse s_params_ImportParse = new ActionParamsClass_ImportParse();
|
static readonly ActionParamsClass_ImportParse s_params_ImportParse = new ActionParamsClass_ImportParse();
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public ActionParamsClass_ImportParse ImportParseParams { get { return s_params_ImportParse; } }
|
public ActionParamsClass_ImportParse ImportParseParams { get { return s_params_ImportParse; } }
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public class ActionParamsClass_ImportParse
|
public class ActionParamsClass_ImportParse
|
||||||
{
|
{
|
||||||
public readonly string ImportFile = "ImportFile";
|
public readonly string Id = "Id";
|
||||||
|
public readonly string Headers = "Headers";
|
||||||
}
|
}
|
||||||
static readonly ActionParamsClass_ImportProcess s_params_ImportProcess = new ActionParamsClass_ImportProcess();
|
static readonly ActionParamsClass_ImportApply s_params_ImportApply = new ActionParamsClass_ImportApply();
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public ActionParamsClass_ImportProcess ImportProcessParams { get { return s_params_ImportProcess; } }
|
public ActionParamsClass_ImportApply ImportApplyParams { get { return s_params_ImportApply; } }
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
public class ActionParamsClass_ImportProcess
|
public class ActionParamsClass_ImportApply
|
||||||
{
|
{
|
||||||
public readonly string ParseTaskSessionKey = "ParseTaskSessionKey";
|
public readonly string Id = "Id";
|
||||||
}
|
}
|
||||||
static readonly ActionParamsClass_Export s_params_Export = new ActionParamsClass_Export();
|
static readonly ActionParamsClass_Export s_params_Export = new ActionParamsClass_Export();
|
||||||
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
|
||||||
@@ -4086,23 +4162,35 @@ namespace Disco.Web.Areas.API.Controllers
|
|||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void ImportParseOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, System.Web.HttpPostedFileBase ImportFile);
|
partial void ImportBeginOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, System.Web.HttpPostedFileBase ImportFile, bool HasHeader);
|
||||||
|
|
||||||
public override System.Web.Mvc.ActionResult ImportParse(System.Web.HttpPostedFileBase ImportFile)
|
public override System.Web.Mvc.ActionResult ImportBegin(System.Web.HttpPostedFileBase ImportFile, bool HasHeader)
|
||||||
{
|
{
|
||||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportParse);
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportBegin);
|
||||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ImportFile", ImportFile);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ImportFile", ImportFile);
|
||||||
ImportParseOverride(callInfo, ImportFile);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "HasHeader", HasHeader);
|
||||||
|
ImportBeginOverride(callInfo, ImportFile, HasHeader);
|
||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
partial void ImportProcessOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string ParseTaskSessionKey);
|
partial void ImportParseOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id, System.Collections.Generic.List<Disco.Models.Services.Devices.Importing.DeviceImportFieldTypes> Headers);
|
||||||
|
|
||||||
public override System.Web.Mvc.ActionResult ImportProcess(string ParseTaskSessionKey)
|
public override System.Web.Mvc.ActionResult ImportParse(string Id, System.Collections.Generic.List<Disco.Models.Services.Devices.Importing.DeviceImportFieldTypes> Headers)
|
||||||
{
|
{
|
||||||
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportProcess);
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportParse);
|
||||||
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ParseTaskSessionKey", ParseTaskSessionKey);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||||
ImportProcessOverride(callInfo, ParseTaskSessionKey);
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Headers", Headers);
|
||||||
|
ImportParseOverride(callInfo, Id, Headers);
|
||||||
|
return callInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void ImportApplyOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
|
||||||
|
|
||||||
|
public override System.Web.Mvc.ActionResult ImportApply(string Id)
|
||||||
|
{
|
||||||
|
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.ImportApply);
|
||||||
|
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
|
||||||
|
ImportApplyOverride(callInfo, Id);
|
||||||
return callInfo;
|
return callInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
</script>
|
</script>
|
||||||
}
|
}
|
||||||
<div id="Devices_Export_Exporting" class="dialog" title="Exporting Devices...">
|
<div id="Devices_Export_Exporting" class="dialog" title="Exporting Devices...">
|
||||||
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Device Exporting devices...</h4>
|
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Exporting devices...</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="actionBar">
|
<div class="actionBar">
|
||||||
<a id="Devices_Export_Button" href="#" class="button">Export Devices</a>
|
<a id="Devices_Export_Button" href="#" class="button">Export Devices</a>
|
||||||
|
|||||||
@@ -640,7 +640,7 @@ WriteLiteral(" class=\"fa fa-lg fa-cog fa-spin\"");
|
|||||||
|
|
||||||
WriteLiteral(" title=\"Please Wait\"");
|
WriteLiteral(" title=\"Please Wait\"");
|
||||||
|
|
||||||
WriteLiteral("></i>Device Exporting devices...</h4>\r\n</div>\r\n<div");
|
WriteLiteral("></i>Exporting devices...</h4>\r\n</div>\r\n<div");
|
||||||
|
|
||||||
WriteLiteral(" class=\"actionBar\"");
|
WriteLiteral(" class=\"actionBar\"");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,232 @@
|
|||||||
|
@model Disco.Web.Models.Device.ImportModel
|
||||||
|
@using Disco.Models.Services.Devices.Importing;
|
||||||
|
@{
|
||||||
|
Authorization.Require(Claims.Device.Actions.Import);
|
||||||
|
|
||||||
|
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices");
|
||||||
|
}
|
||||||
|
<div id="Devices_Import">
|
||||||
|
@using (Html.BeginForm(MVC.API.Device.ImportBegin(), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
||||||
|
{
|
||||||
|
<div id="importDialog" class="form" style="width: 450px">
|
||||||
|
<h2>Import Devices</h2>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
@Html.LabelFor(m => m.ImportFile)
|
||||||
|
</th>
|
||||||
|
<td>
|
||||||
|
<input id="ImportFile" name="ImportFile" type="file" data-val="true" data-val-required="An Import File is required." /><br />
|
||||||
|
@Html.ValidationMessageFor(m => m.ImportFile)
|
||||||
|
<div>
|
||||||
|
@Html.CheckBoxFor(m => m.HasHeader)
|
||||||
|
@Html.LabelFor(m => m.HasHeader)
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<p class="actions">
|
||||||
|
<input type="submit" class="button" value="Begin Import" />
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div id="Devices_Import_Loading_Dialog" class="dialog" title="Loading devices import...">
|
||||||
|
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Loading device import...</h4>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var $Devices_Import_Loading_Dialog = null;
|
||||||
|
|
||||||
|
$('#ImportFile').closest('form').submit(function () {
|
||||||
|
if ($Devices_Import_Loading_Dialog == null) {
|
||||||
|
$Devices_Import_Loading_Dialog = $('#Devices_Import_Loading_Dialog').dialog({
|
||||||
|
width: 400,
|
||||||
|
height: 160,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(function () {
|
||||||
|
$Devices_Import_Loading_Dialog.dialog('open');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
<div id="Devices_Import_Documentation">
|
||||||
|
<h3>CSV Import Specification</h3>
|
||||||
|
<h4>Format</h4>
|
||||||
|
<ul>
|
||||||
|
<li>The import file must be in <strong>comma-separated values format</strong> (<a href="http://en.wikipedia.org/wiki/Comma-separated_values" target="_blank">CSV Reference</a>).</li>
|
||||||
|
<li>Be conscious of editors removing leading zeros from serial numbers (ie: Microsoft Excel).</li>
|
||||||
|
</ul>
|
||||||
|
<h4>Fields</h4>
|
||||||
|
<div class="smallMessage">The following fields/columns are available for to the import file. The Device Serial Number is the only required field, all other fields are optional. Fields can appear in any order.</div>
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 100px;">Field Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var field in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<th>@field.Item2</th>
|
||||||
|
<td>
|
||||||
|
@field.Item3
|
||||||
|
@if (field.Item1 == DeviceImportFieldTypes.DeviceSerialNumber.ToString())
|
||||||
|
{
|
||||||
|
<strong>Required</strong>
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.ModelId.ToString())
|
||||||
|
{
|
||||||
|
<span>(<a href="#" id="Devices_Import_Documentation_DeviceModels_Button">Show IDs</a>)</span>
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.ProfileId.ToString())
|
||||||
|
{
|
||||||
|
<span>(<a href="#" id="Devices_Import_Documentation_DeviceProfiles_Button">Show IDs</a>)</span>
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.BatchId.ToString())
|
||||||
|
{
|
||||||
|
<span>(<a href="#" id="Devices_Import_Documentation_DeviceBatches_Button">Show IDs</a>)</span>
|
||||||
|
}
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="Devices_Import_Documentation_DeviceModels_Dialog" class="dialog" title="Disco Device Model Ids">
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Manufacturer</th>
|
||||||
|
<th>Model</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var dm in Model.DeviceModels)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@Html.ActionLink(dm.Id.ToString(), MVC.Config.DeviceModel.Index(dm.Id))</td>
|
||||||
|
<td>@dm.ToString()</td>
|
||||||
|
<td>@dm.Manufacturer</td>
|
||||||
|
<td>@dm.Model</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="Devices_Import_Documentation_DeviceProfiles_Dialog" class="dialog" title="Disco Device Profile Ids">
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Short Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var dp in Model.DeviceProfiles)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@Html.ActionLink(dp.Id.ToString(), MVC.Config.DeviceProfile.Index(dp.Id))</td>
|
||||||
|
<td>@dp.Name</td>
|
||||||
|
<td>@dp.ShortName</td>
|
||||||
|
<td>@dp.Description</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="Devices_Import_Documentation_DeviceBatches_Dialog" class="dialog" title="Disco Device Batch Ids">
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Purchase Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var db in Model.DeviceBatches)
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
<td>@Html.ActionLink(db.Id.ToString(), MVC.Config.DeviceBatch.Index(db.Id))</td>
|
||||||
|
<td>@db.Name</td>
|
||||||
|
<td>@CommonHelpers.FriendlyDate(db.PurchaseDate)</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var dialogOptions = {
|
||||||
|
width: 700,
|
||||||
|
height: 600,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: false
|
||||||
|
},
|
||||||
|
$DeviceModelsDialog = null,
|
||||||
|
$DeviceProfilesDialog = null,
|
||||||
|
$DeviceBatchesDialog = null;
|
||||||
|
|
||||||
|
$('#Devices_Import_Documentation_DeviceModels_Button').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!$DeviceModelsDialog)
|
||||||
|
$DeviceModelsDialog = $('#Devices_Import_Documentation_DeviceModels_Dialog').dialog(dialogOptions);
|
||||||
|
$DeviceModelsDialog.dialog('open');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#Devices_Import_Documentation_DeviceProfiles_Button').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!$DeviceProfilesDialog)
|
||||||
|
$DeviceProfilesDialog = $('#Devices_Import_Documentation_DeviceProfiles_Dialog').dialog(dialogOptions);
|
||||||
|
$DeviceProfilesDialog.dialog('open');
|
||||||
|
});
|
||||||
|
$('#Devices_Import_Documentation_DeviceBatches_Button').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!$DeviceBatchesDialog)
|
||||||
|
$DeviceBatchesDialog = $('#Devices_Import_Documentation_DeviceBatches_Dialog').dialog(dialogOptions);
|
||||||
|
$DeviceBatchesDialog.dialog('open');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@if (Model.CompletedImportSessionContext != null)
|
||||||
|
{
|
||||||
|
<div id="Devices_Import_Completed_Dialog" class="dialog" title="Device Import Completed">
|
||||||
|
<h3><i class="fa fa-lg fa-check"></i>Successfully imported/updated @Model.CompletedImportSessionContext.AffectedRecords device@(Model.CompletedImportSessionContext.AffectedRecords != 1 ? "s" : null).</h3>
|
||||||
|
<div>File: <code>@Model.CompletedImportSessionContext.Filename</code></div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$('#Devices_Import_Completed_Dialog')
|
||||||
|
.dialog({
|
||||||
|
width: 500,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: true,
|
||||||
|
buttons: {
|
||||||
|
Close: function () {
|
||||||
|
$(this).dialog('destroy');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
@@ -0,0 +1,698 @@
|
|||||||
|
#pragma warning disable 1591
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.34014
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Disco.Web.Views.Device
|
||||||
|
{
|
||||||
|
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.BI.Extensions;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
|
||||||
|
#line 2 "..\..\Views\Device\Import.cshtml"
|
||||||
|
using Disco.Models.Services.Devices.Importing;
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Web;
|
||||||
|
using Disco.Web;
|
||||||
|
using Disco.Web.Extensions;
|
||||||
|
|
||||||
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
|
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/Device/Import.cshtml")]
|
||||||
|
public partial class Import : Disco.Services.Web.WebViewPage<Disco.Web.Models.Device.ImportModel>
|
||||||
|
{
|
||||||
|
public Import()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
|
||||||
|
#line 3 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
Authorization.Require(Claims.Device.Actions.Import);
|
||||||
|
|
||||||
|
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices");
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n<div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 9 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 9 "..\..\Views\Device\Import.cshtml"
|
||||||
|
using (Html.BeginForm(MVC.API.Device.ImportBegin(), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"importDialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"form\"");
|
||||||
|
|
||||||
|
WriteLiteral(" style=\"width: 450px\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <h2>Import Devices</h2>\r\n <table>\r\n <tr>" +
|
||||||
|
"\r\n <th>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 16 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.LabelFor(m => m.ImportFile));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n </th>\r\n <td>\r\n <i" +
|
||||||
|
"nput");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"ImportFile\"");
|
||||||
|
|
||||||
|
WriteLiteral(" name=\"ImportFile\"");
|
||||||
|
|
||||||
|
WriteLiteral(" type=\"file\"");
|
||||||
|
|
||||||
|
WriteLiteral(" data-val=\"true\"");
|
||||||
|
|
||||||
|
WriteLiteral(" data-val-required=\"An Import File is required.\"");
|
||||||
|
|
||||||
|
WriteLiteral(" /><br />\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 20 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.ValidationMessageFor(m => m.ImportFile));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n <div>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 22 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.CheckBoxFor(m => m.HasHeader));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 23 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.LabelFor(m => m.HasHeader));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n </div>\r\n </td>\r\n </tr" +
|
||||||
|
">\r\n </table>\r\n <p");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"actions\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <input");
|
||||||
|
|
||||||
|
WriteLiteral(" type=\"submit\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"button\"");
|
||||||
|
|
||||||
|
WriteLiteral(" value=\"Begin Import\"");
|
||||||
|
|
||||||
|
WriteLiteral(" />\r\n </p>\r\n </div>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Loading_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Loading devices import...\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <h4><i");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"fa fa-lg fa-cog fa-spin\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Please Wait\"");
|
||||||
|
|
||||||
|
WriteLiteral("></i>Loading device import...</h4>\r\n </div>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(@" <script>
|
||||||
|
$(function () {
|
||||||
|
var $Devices_Import_Loading_Dialog = null;
|
||||||
|
|
||||||
|
$('#ImportFile').closest('form').submit(function () {
|
||||||
|
if ($Devices_Import_Loading_Dialog == null) {
|
||||||
|
$Devices_Import_Loading_Dialog = $('#Devices_Import_Loading_Dialog').dialog({
|
||||||
|
width: 400,
|
||||||
|
height: 160,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setTimeout(function () {
|
||||||
|
$Devices_Import_Loading_Dialog.dialog('open');
|
||||||
|
}, 200);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
#line 56 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <h3>CSV Import Specification</h3>\r\n <h4>Format</h4>\r\n <u" +
|
||||||
|
"l>\r\n <li>The import file must be in <strong>comma-separated values fo" +
|
||||||
|
"rmat</strong> (<a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"http://en.wikipedia.org/wiki/Comma-separated_values\"");
|
||||||
|
|
||||||
|
WriteLiteral(" target=\"_blank\"");
|
||||||
|
|
||||||
|
WriteLiteral(">CSV Reference</a>).</li>\r\n <li>Be conscious of editors removing leadi" +
|
||||||
|
"ng zeros from serial numbers (ie: Microsoft Excel).</li>\r\n </ul>\r\n " +
|
||||||
|
" <h4>Fields</h4>\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"smallMessage\"");
|
||||||
|
|
||||||
|
WriteLiteral(">The following fields/columns are available for to the import file. The Device Se" +
|
||||||
|
"rial Number is the only required field, all other fields are optional. Fields ca" +
|
||||||
|
"n appear in any order.</div>\r\n <table");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"tableData\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <thead>\r\n <tr>\r\n <th");
|
||||||
|
|
||||||
|
WriteLiteral(" style=\"width: 100px;\"");
|
||||||
|
|
||||||
|
WriteLiteral(">Field Name</th>\r\n <th>Description</th>\r\n </tr>" +
|
||||||
|
"\r\n </thead>\r\n <tbody>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 74 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 74 "..\..\Views\Device\Import.cshtml"
|
||||||
|
foreach (var field in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <tr>\r\n <th>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 77 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(field.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</th>\r\n <td>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 79 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(field.Item3);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 80 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 80 "..\..\Views\Device\Import.cshtml"
|
||||||
|
if (field.Item1 == DeviceImportFieldTypes.DeviceSerialNumber.ToString())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <strong>Required</strong>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 83 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.ModelId.ToString())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <span>(<a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceModels_Button\"");
|
||||||
|
|
||||||
|
WriteLiteral(">Show IDs</a>)</span>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 87 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.ProfileId.ToString())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <span>(<a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceProfiles_Button\"");
|
||||||
|
|
||||||
|
WriteLiteral(">Show IDs</a>)</span>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 91 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
else if (field.Item1 == DeviceImportFieldTypes.BatchId.ToString())
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <span>(<a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceBatches_Button\"");
|
||||||
|
|
||||||
|
WriteLiteral(">Show IDs</a>)</span>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 95 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n </td>\r\n </tr> \r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 99 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tbody>\r\n </table>\r\n\r\n\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceModels_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Disco Device Model Ids\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <table");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"tableData\"");
|
||||||
|
|
||||||
|
WriteLiteral(@">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Manufacturer</th>
|
||||||
|
<th>Model</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
#line 115 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 115 "..\..\Views\Device\Import.cshtml"
|
||||||
|
foreach (var dm in Model.DeviceModels)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <tr>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 118 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.ActionLink(dm.Id.ToString(), MVC.Config.DeviceModel.Index(dm.Id)));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 119 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dm.ToString());
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 120 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dm.Manufacturer);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 121 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dm.Model);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 123 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceProfiles_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Disco Device Profile Ids\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <table");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"tableData\"");
|
||||||
|
|
||||||
|
WriteLiteral(@">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Short Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
#line 139 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 139 "..\..\Views\Device\Import.cshtml"
|
||||||
|
foreach (var dp in Model.DeviceProfiles)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <tr>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 142 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.ActionLink(dp.Id.ToString(), MVC.Config.DeviceProfile.Index(dp.Id)));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 143 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dp.Name);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 144 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dp.ShortName);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 145 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(dp.Description);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 147 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Documentation_DeviceBatches_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Disco Device Batch Ids\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <table");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"tableData\"");
|
||||||
|
|
||||||
|
WriteLiteral(@">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Purchase Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
#line 162 "..\..\Views\Device\Import.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 162 "..\..\Views\Device\Import.cshtml"
|
||||||
|
foreach (var db in Model.DeviceBatches)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <tr>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 165 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Html.ActionLink(db.Id.ToString(), MVC.Config.DeviceBatch.Index(db.Id)));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 166 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(db.Name);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n <td>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 167 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(CommonHelpers.FriendlyDate(db.PurchaseDate));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n </tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 169 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <script" +
|
||||||
|
">\r\n $(function () {\r\n var dialogOptions = {\r\n " +
|
||||||
|
" width: 700,\r\n height: 600,\r\n re" +
|
||||||
|
"sizable: false,\r\n modal: true,\r\n autoOpen:" +
|
||||||
|
" false\r\n },\r\n $DeviceModelsDialog = null,\r\n " +
|
||||||
|
" $DeviceProfilesDialog = null,\r\n $DeviceBatchesDialog = n" +
|
||||||
|
"ull;\r\n\r\n $(\'#Devices_Import_Documentation_DeviceModels_Button\').c" +
|
||||||
|
"lick(function (e) {\r\n e.preventDefault();\r\n " +
|
||||||
|
" if (!$DeviceModelsDialog)\r\n $DeviceModelsDialog = $(\'#D" +
|
||||||
|
"evices_Import_Documentation_DeviceModels_Dialog\').dialog(dialogOptions);\r\n " +
|
||||||
|
" $DeviceModelsDialog.dialog(\'open\');\r\n });\r\n\r\n " +
|
||||||
|
" $(\'#Devices_Import_Documentation_DeviceProfiles_Button\').click(functio" +
|
||||||
|
"n (e) {\r\n e.preventDefault();\r\n if (!$Devi" +
|
||||||
|
"ceProfilesDialog)\r\n $DeviceProfilesDialog = $(\'#Devices_I" +
|
||||||
|
"mport_Documentation_DeviceProfiles_Dialog\').dialog(dialogOptions);\r\n " +
|
||||||
|
" $DeviceProfilesDialog.dialog(\'open\');\r\n });\r\n " +
|
||||||
|
" $(\'#Devices_Import_Documentation_DeviceBatches_Button\').click(function (e) {" +
|
||||||
|
"\r\n e.preventDefault();\r\n if (!$DeviceBatch" +
|
||||||
|
"esDialog)\r\n $DeviceBatchesDialog = $(\'#Devices_Import_Doc" +
|
||||||
|
"umentation_DeviceBatches_Dialog\').dialog(dialogOptions);\r\n $D" +
|
||||||
|
"eviceBatchesDialog.dialog(\'open\');\r\n });\r\n });\r\n " +
|
||||||
|
" </script>\r\n </div>\r\n</div>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 210 "..\..\Views\Device\Import.cshtml"
|
||||||
|
if (Model.CompletedImportSessionContext != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Completed_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Device Import Completed\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <h3><i");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"fa fa-lg fa-check\"");
|
||||||
|
|
||||||
|
WriteLiteral("></i>Successfully imported/updated ");
|
||||||
|
|
||||||
|
|
||||||
|
#line 213 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Model.CompletedImportSessionContext.AffectedRecords);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" device");
|
||||||
|
|
||||||
|
|
||||||
|
#line 213 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Model.CompletedImportSessionContext.AffectedRecords != 1 ? "s" : null);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(".</h3>\r\n <div>File: <code>");
|
||||||
|
|
||||||
|
|
||||||
|
#line 214 "..\..\Views\Device\Import.cshtml"
|
||||||
|
Write(Model.CompletedImportSessionContext.Filename);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</code></div>\r\n </div>\r\n");
|
||||||
|
|
||||||
|
WriteLiteral(@" <script>
|
||||||
|
$(function () {
|
||||||
|
$('#Devices_Import_Completed_Dialog')
|
||||||
|
.dialog({
|
||||||
|
width: 500,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: true,
|
||||||
|
buttons: {
|
||||||
|
Close: function () {
|
||||||
|
$(this).dialog('destroy');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
");
|
||||||
|
|
||||||
|
|
||||||
|
#line 232 "..\..\Views\Device\Import.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore 1591
|
||||||
@@ -1,192 +0,0 @@
|
|||||||
@model Disco.Web.Models.Device.ImportModel
|
|
||||||
@{
|
|
||||||
Authorization.RequireAny(Claims.Device.Actions.Import, Claims.Device.Actions.Export);
|
|
||||||
|
|
||||||
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import/Export Devices");
|
|
||||||
}
|
|
||||||
@if (Authorization.Has(Claims.Device.Actions.Import)){
|
|
||||||
<div id="deviceImport">
|
|
||||||
@using (Html.BeginForm(MVC.API.Device.ImportParse(), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
|
||||||
{
|
|
||||||
@Html.ValidationSummary()
|
|
||||||
<div id="importDialog" class="form" style="width: 450px">
|
|
||||||
<h2>Import Devices</h2>
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
@Html.LabelFor(m => m.ImportFile)
|
|
||||||
</th>
|
|
||||||
<td>
|
|
||||||
<input id="ImportFile" name="ImportFile" type="file" data-val="true" data-val-required="An Import File is required." />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<p class="actions">
|
|
||||||
<input type="submit" class="button" value="Import" />
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div id="documentation">
|
|
||||||
<h3>CSV Import Specification</h3>
|
|
||||||
<h4>Format</h4>
|
|
||||||
<ul>
|
|
||||||
<li>The import file must be in <strong>comma-separated values format</strong> (<a href="http://en.wikipedia.org/wiki/Comma-separated_values" target="_blank">CSV Reference</a>).</li>
|
|
||||||
<li>The <strong>first line will be ignored</strong> (it is assumed the file includes headers).</li>
|
|
||||||
<li>Be conscious of editors removing leading zeros from serial numbers (ie: Microsoft Excel).</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Fields</h4>
|
|
||||||
<div class="smallMessage">The following fields/columns are available for to the import file. The <strong>order of the fields</strong> must be as shown below.</div>
|
|
||||||
<table class="tableData">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="width: 100px;">Field Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>Serial Number</th>
|
|
||||||
<td><strong>Required</strong> - must contain the device serial number (maximum of 60 characters).
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Device Model</th>
|
|
||||||
<td>The <span class="code">ID</span> for the Device Model (<a href="#" id="showDeviceModels">Show IDs</a>). <em>Default: <span class="code">1</span> [@Html.ActionLink(Model.DeviceModels[0].ToString(), MVC.Config.DeviceModel.Index(Model.DeviceModels[0].Id))]</em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Device Profile</th>
|
|
||||||
<td>The <span class="code">ID</span> for the Device Profile (<a href="#" id="showDeviceProfiles">Show IDs</a>). <em>Default: <span class="code">1</span> [@Html.ActionLink(Model.DeviceProfiles[0].ToString(), MVC.Config.DeviceProfile.Index(Model.DeviceProfiles[0].Id))]</em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Device Batch</th>
|
|
||||||
<td>The <span class="code">ID</span> for the Device Batch (<a href="#" id="showDeviceBatches">Show IDs</a>). <em>Default: <span class="code"><None></span></em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Assigned User</th>
|
|
||||||
<td>The <span class="code">ID</span> for the User assigned to the device. <em>Default: <span class="code"><None></span></em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Location</th>
|
|
||||||
<td>Updates the Location of the device. Maximum of 250 characters. <em>Default: <span class="code"><None></span></em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Asset Number</th>
|
|
||||||
<td>Updates the Asset Number of the device. Maximum of 40 characters. <em>Default: <span class="code"><None></span></em>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="showDeviceModelsDialog" class="hiddenDialog" title="Disco Device Model Ids">
|
|
||||||
<table class="tableData">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Manufacturer</th>
|
|
||||||
<th>Model</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var dm in Model.DeviceModels)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>@Html.ActionLink(dm.Id.ToString(), MVC.Config.DeviceModel.Index(dm.Id))</td>
|
|
||||||
<td>@dm.ToString()</td>
|
|
||||||
<td>@dm.Manufacturer</td>
|
|
||||||
<td>@dm.Model</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="showDeviceProfilesDialog" class="hiddenDialog" title="Disco Device Profile Ids">
|
|
||||||
<table class="tableData">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Short Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var dp in Model.DeviceProfiles)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>@Html.ActionLink(dp.Id.ToString(), MVC.Config.DeviceProfile.Index(dp.Id))</td>
|
|
||||||
<td>@dp.Name</td>
|
|
||||||
<td>@dp.ShortName</td>
|
|
||||||
<td>@dp.Description</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="showDeviceBatchesDialog" class="hiddenDialog" title="Disco Device Batch Ids">
|
|
||||||
<table class="tableData">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Purchase Date</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@foreach (var db in Model.DeviceBatches)
|
|
||||||
{
|
|
||||||
<tr>
|
|
||||||
<td>@Html.ActionLink(db.Id.ToString(), MVC.Config.DeviceBatch.Index(db.Id))</td>
|
|
||||||
<td>@db.Name</td>
|
|
||||||
<td>@CommonHelpers.FriendlyDate(db.PurchaseDate)</td>
|
|
||||||
</tr>
|
|
||||||
}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
$(function () {
|
|
||||||
var dialogOptions = {
|
|
||||||
width: 700,
|
|
||||||
height: 600,
|
|
||||||
resizable: false,
|
|
||||||
modal: true,
|
|
||||||
autoOpen: false
|
|
||||||
},
|
|
||||||
$showDeviceModelsDialog = null,
|
|
||||||
$showDeviceProfilesDialog = null,
|
|
||||||
$showDeviceBatchesDialog = null;
|
|
||||||
|
|
||||||
$('#showDeviceModels').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!$showDeviceModelsDialog)
|
|
||||||
$showDeviceModelsDialog = $('#showDeviceModelsDialog').dialog(dialogOptions);
|
|
||||||
$showDeviceModelsDialog.dialog('open');
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#showDeviceProfiles').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!$showDeviceProfilesDialog)
|
|
||||||
$showDeviceProfilesDialog = $('#showDeviceProfilesDialog').dialog(dialogOptions);
|
|
||||||
$showDeviceProfilesDialog.dialog('open');
|
|
||||||
});
|
|
||||||
$('#showDeviceBatches').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
if (!$showDeviceBatchesDialog)
|
|
||||||
$showDeviceBatchesDialog = $('#showDeviceBatchesDialog').dialog(dialogOptions);
|
|
||||||
$showDeviceBatchesDialog.dialog('open');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
@@ -1,553 +0,0 @@
|
|||||||
#pragma warning disable 1591
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
// <auto-generated>
|
|
||||||
// This code was generated by a tool.
|
|
||||||
// Runtime Version:4.0.30319.34014
|
|
||||||
//
|
|
||||||
// Changes to this file may cause incorrect behavior and will be lost if
|
|
||||||
// the code is regenerated.
|
|
||||||
// </auto-generated>
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
namespace Disco.Web.Views.Device
|
|
||||||
{
|
|
||||||
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.BI.Extensions;
|
|
||||||
using Disco.Models.Repository;
|
|
||||||
using Disco.Services;
|
|
||||||
using Disco.Services.Authorization;
|
|
||||||
using Disco.Services.Web;
|
|
||||||
using Disco.Web;
|
|
||||||
using Disco.Web.Extensions;
|
|
||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
|
||||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/Device/ImportExport.cshtml")]
|
|
||||||
public partial class ImportExport : Disco.Services.Web.WebViewPage<Disco.Web.Models.Device.ImportModel>
|
|
||||||
{
|
|
||||||
public ImportExport()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
public override void Execute()
|
|
||||||
{
|
|
||||||
|
|
||||||
#line 2 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
Authorization.RequireAny(Claims.Device.Actions.Import, Claims.Device.Actions.Export);
|
|
||||||
|
|
||||||
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import/Export Devices");
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 7 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
if (Authorization.Has(Claims.Device.Actions.Import)){
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("<div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"deviceImport\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 9 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 9 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
using (Html.BeginForm(MVC.API.Device.ImportParse(), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 11 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ValidationSummary());
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 11 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" <div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"importDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"form\"");
|
|
||||||
|
|
||||||
WriteLiteral(" style=\"width: 450px\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <h2>Import Devices</h2>\r\n <table>\r\n <tr>" +
|
|
||||||
"\r\n <th>\r\n");
|
|
||||||
|
|
||||||
WriteLiteral(" ");
|
|
||||||
|
|
||||||
|
|
||||||
#line 17 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.LabelFor(m => m.ImportFile));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("\r\n </th>\r\n <td>\r\n <i" +
|
|
||||||
"nput");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"ImportFile\"");
|
|
||||||
|
|
||||||
WriteLiteral(" name=\"ImportFile\"");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"file\"");
|
|
||||||
|
|
||||||
WriteLiteral(" data-val=\"true\"");
|
|
||||||
|
|
||||||
WriteLiteral(" data-val-required=\"An Import File is required.\"");
|
|
||||||
|
|
||||||
WriteLiteral(" />\r\n </td>\r\n </tr>\r\n </table>\r\n " +
|
|
||||||
" <p");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"actions\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <input");
|
|
||||||
|
|
||||||
WriteLiteral(" type=\"submit\"");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"button\"");
|
|
||||||
|
|
||||||
WriteLiteral(" value=\"Import\"");
|
|
||||||
|
|
||||||
WriteLiteral(" />\r\n </p>\r\n </div>\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 28 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" <div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"documentation\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <h3>CSV Import Specification</h3>\r\n <h4>Format</h4>\r\n <u" +
|
|
||||||
"l>\r\n <li>The import file must be in <strong>comma-separated values fo" +
|
|
||||||
"rmat</strong> (<a");
|
|
||||||
|
|
||||||
WriteLiteral(" href=\"http://en.wikipedia.org/wiki/Comma-separated_values\"");
|
|
||||||
|
|
||||||
WriteLiteral(" target=\"_blank\"");
|
|
||||||
|
|
||||||
WriteLiteral(@">CSV Reference</a>).</li>
|
|
||||||
<li>The <strong>first line will be ignored</strong> (it is assumed the file includes headers).</li>
|
|
||||||
<li>Be conscious of editors removing leading zeros from serial numbers (ie: Microsoft Excel).</li>
|
|
||||||
</ul>
|
|
||||||
<h4>Fields</h4>
|
|
||||||
<div");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"smallMessage\"");
|
|
||||||
|
|
||||||
WriteLiteral(">The following fields/columns are available for to the import file. The <strong>o" +
|
|
||||||
"rder of the fields</strong> must be as shown below.</div>\r\n <table");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"tableData\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <thead>\r\n <tr>\r\n <th");
|
|
||||||
|
|
||||||
WriteLiteral(" style=\"width: 100px;\"");
|
|
||||||
|
|
||||||
WriteLiteral(@">Field Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<th>Serial Number</th>
|
|
||||||
<td><strong>Required</strong> - must contain the device serial number (maximum of 60 characters).
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>Device Model</th>
|
|
||||||
<td>The <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">ID</span> for the Device Model (<a");
|
|
||||||
|
|
||||||
WriteLiteral(" href=\"#\"");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceModels\"");
|
|
||||||
|
|
||||||
WriteLiteral(">Show IDs</a>). <em>Default: <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">1</span> [");
|
|
||||||
|
|
||||||
|
|
||||||
#line 54 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ActionLink(Model.DeviceModels[0].ToString(), MVC.Config.DeviceModel.Index(Model.DeviceModels[0].Id)));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("]</em>\r\n </td>\r\n </tr>\r\n <tr>\r\n " +
|
|
||||||
" <th>Device Profile</th>\r\n <td>The <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">ID</span> for the Device Profile (<a");
|
|
||||||
|
|
||||||
WriteLiteral(" href=\"#\"");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceProfiles\"");
|
|
||||||
|
|
||||||
WriteLiteral(">Show IDs</a>). <em>Default: <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">1</span> [");
|
|
||||||
|
|
||||||
|
|
||||||
#line 59 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ActionLink(Model.DeviceProfiles[0].ToString(), MVC.Config.DeviceProfile.Index(Model.DeviceProfiles[0].Id)));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("]</em>\r\n </td>\r\n </tr>\r\n <tr>\r\n " +
|
|
||||||
" <th>Device Batch</th>\r\n <td>The <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">ID</span> for the Device Batch (<a");
|
|
||||||
|
|
||||||
WriteLiteral(" href=\"#\"");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceBatches\"");
|
|
||||||
|
|
||||||
WriteLiteral(">Show IDs</a>). <em>Default: <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral("><None></span></em>\r\n </td>\r\n </tr>\r\n " +
|
|
||||||
" <tr>\r\n <th>Assigned User</th>\r\n " +
|
|
||||||
" <td>The <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral(">ID</span> for the User assigned to the device. <em>Default: <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral("><None></span></em>\r\n </td>\r\n </tr>\r\n " +
|
|
||||||
" <tr>\r\n <th>Location</th>\r\n <td" +
|
|
||||||
">Updates the Location of the device. Maximum of 250 characters. <em>Default: <sp" +
|
|
||||||
"an");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral("><None></span></em>\r\n </td>\r\n </tr>\r\n " +
|
|
||||||
" <tr>\r\n <th>Asset Number</th>\r\n " +
|
|
||||||
" <td>Updates the Asset Number of the device. Maximum of 40 characters. <em>Defau" +
|
|
||||||
"lt: <span");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"code\"");
|
|
||||||
|
|
||||||
WriteLiteral("><None></span></em>\r\n </td>\r\n </tr>\r\n " +
|
|
||||||
" </tbody>\r\n </table>\r\n\r\n\r\n <div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceModelsDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"hiddenDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" title=\"Disco Device Model Ids\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <table");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"tableData\"");
|
|
||||||
|
|
||||||
WriteLiteral(@">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Manufacturer</th>
|
|
||||||
<th>Model</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
");
|
|
||||||
|
|
||||||
|
|
||||||
#line 97 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 97 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
foreach (var dm in Model.DeviceModels)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" <tr>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 100 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ActionLink(dm.Id.ToString(), MVC.Config.DeviceModel.Index(dm.Id)));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 101 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dm.ToString());
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 102 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dm.Manufacturer);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 103 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dm.Model);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 105 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceProfilesDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"hiddenDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" title=\"Disco Device Profile Ids\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <table");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"tableData\"");
|
|
||||||
|
|
||||||
WriteLiteral(@">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Short Name</th>
|
|
||||||
<th>Description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
");
|
|
||||||
|
|
||||||
|
|
||||||
#line 121 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 121 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
foreach (var dp in Model.DeviceProfiles)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" <tr>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 124 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ActionLink(dp.Id.ToString(), MVC.Config.DeviceProfile.Index(dp.Id)));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 125 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dp.Name);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 126 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dp.ShortName);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 127 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(dp.Description);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 129 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <div");
|
|
||||||
|
|
||||||
WriteLiteral(" id=\"showDeviceBatchesDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"hiddenDialog\"");
|
|
||||||
|
|
||||||
WriteLiteral(" title=\"Disco Device Batch Ids\"");
|
|
||||||
|
|
||||||
WriteLiteral(">\r\n <table");
|
|
||||||
|
|
||||||
WriteLiteral(" class=\"tableData\"");
|
|
||||||
|
|
||||||
WriteLiteral(@">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Purchase Date</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
");
|
|
||||||
|
|
||||||
|
|
||||||
#line 144 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
|
|
||||||
#line 144 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
foreach (var db in Model.DeviceBatches)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" <tr>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 147 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(Html.ActionLink(db.Id.ToString(), MVC.Config.DeviceBatch.Index(db.Id)));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 148 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(db.Name);
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n <td>");
|
|
||||||
|
|
||||||
|
|
||||||
#line 149 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
Write(CommonHelpers.FriendlyDate(db.PurchaseDate));
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral("</td>\r\n </tr>\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 151 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n\r\n <script" +
|
|
||||||
">\r\n $(function () {\r\n var dialogOptions = {\r\n " +
|
|
||||||
" width: 700,\r\n height: 600,\r\n re" +
|
|
||||||
"sizable: false,\r\n modal: true,\r\n autoOpen:" +
|
|
||||||
" false\r\n },\r\n $showDeviceModelsDialog = null,\r\n " +
|
|
||||||
" $showDeviceProfilesDialog = null,\r\n $showDeviceBatch" +
|
|
||||||
"esDialog = null;\r\n\r\n $(\'#showDeviceModels\').click(function (e) {\r" +
|
|
||||||
"\n e.preventDefault();\r\n if (!$showDeviceMo" +
|
|
||||||
"delsDialog)\r\n $showDeviceModelsDialog = $(\'#showDeviceMod" +
|
|
||||||
"elsDialog\').dialog(dialogOptions);\r\n $showDeviceModelsDialog." +
|
|
||||||
"dialog(\'open\');\r\n });\r\n\r\n $(\'#showDeviceProfiles\')" +
|
|
||||||
".click(function (e) {\r\n e.preventDefault();\r\n " +
|
|
||||||
" if (!$showDeviceProfilesDialog)\r\n $showDeviceProfiles" +
|
|
||||||
"Dialog = $(\'#showDeviceProfilesDialog\').dialog(dialogOptions);\r\n " +
|
|
||||||
" $showDeviceProfilesDialog.dialog(\'open\');\r\n });\r\n " +
|
|
||||||
" $(\'#showDeviceBatches\').click(function (e) {\r\n e.preventD" +
|
|
||||||
"efault();\r\n if (!$showDeviceBatchesDialog)\r\n " +
|
|
||||||
" $showDeviceBatchesDialog = $(\'#showDeviceBatchesDialog\').dialog(dialogOpt" +
|
|
||||||
"ions);\r\n $showDeviceBatchesDialog.dialog(\'open\');\r\n " +
|
|
||||||
" });\r\n });\r\n </script>\r\n </div>\r\n</div>\r\n");
|
|
||||||
|
|
||||||
|
|
||||||
#line 192 "..\..\Views\Device\ImportExport.cshtml"
|
|
||||||
}
|
|
||||||
|
|
||||||
#line default
|
|
||||||
#line hidden
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#pragma warning restore 1591
|
|
||||||
@@ -0,0 +1,183 @@
|
|||||||
|
@model Disco.Web.Models.Device.ImportHeadersModel
|
||||||
|
@{
|
||||||
|
Authorization.Require(Claims.Device.Actions.Import);
|
||||||
|
|
||||||
|
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices", MVC.Device.Import(), string.Format("File: {0}", Model.Context.Filename));
|
||||||
|
}
|
||||||
|
<div id="Devices_Import_Headers">
|
||||||
|
|
||||||
|
<h2>Define Import Columns</h2>
|
||||||
|
|
||||||
|
@if (Model.Context.RawData.Count > 10)
|
||||||
|
{
|
||||||
|
<h4 class="alert">@Model.Context.RawData.Count records were loaded, only the first 10 are shown here.</h4>
|
||||||
|
}
|
||||||
|
|
||||||
|
<h4 id="Devices_Import_Headers_DeviceSerialNumberRequired" class="error">The Device Serial Number column must be defined.</h4>
|
||||||
|
|
||||||
|
<div id="Devices_Import_Headers_TableContainer">
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
@foreach (var header in Model.Context.Header.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
<th data-headerindex="@header.Item2" class="header@(header.Item1.Item2.ToString())">@header.Item1.Item1</th>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
@foreach (var header in Model.Context.Header.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
<td data-headerindex="@header.Item2" class="header@(header.Item1.Item2.ToString())">
|
||||||
|
<ul class="importHeaderType" data-headerindex="@header.Item2" data-headertype="@header.Item1.Item2.ToString()">
|
||||||
|
<li><a href="#"><span class="headerTypeTitle">@(Model.HeaderTypes.FirstOrDefault(h => h.Item1 == header.Item1.Item2).Item2)</span></a>
|
||||||
|
<ul>
|
||||||
|
@foreach (var headerType in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
<li data-headertype="@headerType.Item1"><a href="#">@headerType.Item2</a></li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var record in Model.Context.RawData.Take(10))
|
||||||
|
{
|
||||||
|
<tr>
|
||||||
|
@foreach (var field in record.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
<td data-headerindex="@field.Item2">@field.Item1</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="actionBar">
|
||||||
|
@using (Html.BeginForm(MVC.API.Device.ImportParse(Model.Context.SessionId, null)))
|
||||||
|
{
|
||||||
|
<a id="Devices_Import_Headers_Submit" href="#" class="button">Parse Device Import</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="Devices_Import_Parsing_Dialog" class="dialog" title="Parsing devices import...">
|
||||||
|
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Parsing device import...</h4>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
var headerTypes = {
|
||||||
|
@foreach (var h in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
<text>'@(h.Item1)': '@(h.Item2)',</text>
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var $Devices_Import_Headers_TableContainer = $('#Devices_Import_Headers_TableContainer');
|
||||||
|
var $importHeaderTypes = $Devices_Import_Headers_TableContainer.find('thead').find('ul.importHeaderType');
|
||||||
|
var $Devices_Import_Headers_DeviceSerialNumberRequired = $('#Devices_Import_Headers_DeviceSerialNumberRequired');
|
||||||
|
var $Devices_Import_Headers_Submit = $('#Devices_Import_Headers_Submit');
|
||||||
|
var $Devices_Import_Parsing_Dialog = null;
|
||||||
|
|
||||||
|
function getUsedHeaders() {
|
||||||
|
return $importHeaderTypes.map(function () { return $(this).attr('data-headertype'); }).filter(function () { return this != 'IgnoreColumn' }).get();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHeaderOptions() {
|
||||||
|
var usedHeaders = getUsedHeaders();
|
||||||
|
var deviceSerialNumberPresent = (usedHeaders.indexOf('DeviceSerialNumber') >= 0);
|
||||||
|
|
||||||
|
if (deviceSerialNumberPresent) {
|
||||||
|
$Devices_Import_Headers_Submit.attr('disabled', null);
|
||||||
|
$Devices_Import_Headers_DeviceSerialNumberRequired.hide();
|
||||||
|
} else {
|
||||||
|
$Devices_Import_Headers_DeviceSerialNumberRequired.show();
|
||||||
|
$Devices_Import_Headers_Submit.attr('disabled', 'disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
$importHeaderTypes.each(function () {
|
||||||
|
var $header = $(this);
|
||||||
|
var $headerType = $header.attr('data-headertype');
|
||||||
|
$header.find('li[data-headertype]').each(function () {
|
||||||
|
var $headerOption = $(this);
|
||||||
|
var $headerOptionType = $headerOption.attr('data-headertype');
|
||||||
|
if ($headerOptionType === $headerType) {
|
||||||
|
$headerOption.removeClass('ui-state-disabled');
|
||||||
|
$headerOption.addClass('ui-state-highlight');
|
||||||
|
} else if (usedHeaders.indexOf($headerOptionType) < 0) {
|
||||||
|
$headerOption.removeClass('ui-state-disabled ui-state-highlight');
|
||||||
|
} else {
|
||||||
|
$headerOption.removeClass('ui-state-highlight');
|
||||||
|
$headerOption.addClass('ui-state-disabled');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDataStyle(index, headerType) {
|
||||||
|
$Devices_Import_Headers_TableContainer.find('tbody').find('td[data-headerindex="' + index + '"]').removeClass().addClass('header' + headerType);
|
||||||
|
$Devices_Import_Headers_TableContainer.find('thead').find('td[data-headerindex="' + index + '"], th[data-headerindex="' + index + '"]').removeClass().addClass('header' + headerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
$Devices_Import_Headers_TableContainer.find('thead').on('menuselect', 'ul.importHeaderType', function (e, ui) {
|
||||||
|
var headerType = ui.item.attr('data-headertype');
|
||||||
|
|
||||||
|
if (headerType !== undefined) {
|
||||||
|
var $this = $(this).closest('ul.importHeaderType');
|
||||||
|
var headerIndex = $this.attr('data-headerindex');
|
||||||
|
var headerTypeName = headerTypes[headerType];
|
||||||
|
$this.attr('data-headertype', headerType).find('span.headerTypeTitle').text(headerTypeName);
|
||||||
|
updateDataStyle(headerIndex, headerType);
|
||||||
|
updateHeaderOptions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add Type Options
|
||||||
|
$importHeaderTypes.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var thisHeaderIndex = $this.attr('data-headerindex');
|
||||||
|
var thisHeaderType = $this.attr('data-headertype');
|
||||||
|
updateDataStyle(thisHeaderIndex, thisHeaderType);
|
||||||
|
}).menu({ position: { my: "left top", at: "left bottom" } });
|
||||||
|
|
||||||
|
updateHeaderOptions();
|
||||||
|
|
||||||
|
$('#Devices_Import_Headers_Submit').click(function () {
|
||||||
|
|
||||||
|
// Validate Device Serial Number Present
|
||||||
|
var usedHeaders = getUsedHeaders();
|
||||||
|
var deviceSerialNumberPresent = (usedHeaders.indexOf('DeviceSerialNumber') >= 0);
|
||||||
|
if (!deviceSerialNumberPresent) {
|
||||||
|
updateHeaderOptions();
|
||||||
|
$Devices_Import_Headers_DeviceSerialNumberRequired.show('highlight');
|
||||||
|
} else {
|
||||||
|
var $form = $(this).closest('form');
|
||||||
|
|
||||||
|
// Build Form
|
||||||
|
$importHeaderTypes.each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var thisHeaderIndex = $this.attr('data-headerindex');
|
||||||
|
var thisHeaderType = $this.attr('data-headertype');
|
||||||
|
|
||||||
|
$(document.createElement('input')).attr({ type: 'hidden', name: 'Headers[' + thisHeaderIndex + ']', value: thisHeaderType }).appendTo($form);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Submit Form
|
||||||
|
if ($Devices_Import_Parsing_Dialog == null) {
|
||||||
|
$Devices_Import_Parsing_Dialog = $('#Devices_Import_Parsing_Dialog').dialog({
|
||||||
|
width: 400,
|
||||||
|
height: 160,
|
||||||
|
resizable: false,
|
||||||
|
modal: true,
|
||||||
|
autoOpen: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$Devices_Import_Parsing_Dialog.dialog('open');
|
||||||
|
$form.submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,557 @@
|
|||||||
|
#pragma warning disable 1591
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.34014
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace Disco.Web.Views.Device
|
||||||
|
{
|
||||||
|
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.BI.Extensions;
|
||||||
|
using Disco.Models.Repository;
|
||||||
|
using Disco.Services;
|
||||||
|
using Disco.Services.Authorization;
|
||||||
|
using Disco.Services.Web;
|
||||||
|
using Disco.Web;
|
||||||
|
using Disco.Web.Extensions;
|
||||||
|
|
||||||
|
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||||
|
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/Device/ImportHeaders.cshtml")]
|
||||||
|
public partial class ImportHeaders : Disco.Services.Web.WebViewPage<Disco.Web.Models.Device.ImportHeadersModel>
|
||||||
|
{
|
||||||
|
public ImportHeaders()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public override void Execute()
|
||||||
|
{
|
||||||
|
|
||||||
|
#line 2 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
Authorization.Require(Claims.Device.Actions.Import);
|
||||||
|
|
||||||
|
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices", MVC.Device.Import(), string.Format("File: {0}", Model.Context.Filename));
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n<div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Headers\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n\r\n <h2>Define Import Columns</h2>\r\n\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 11 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 11 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
if (Model.Context.RawData.Count > 10)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <h4");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"alert\"");
|
||||||
|
|
||||||
|
WriteLiteral(">");
|
||||||
|
|
||||||
|
|
||||||
|
#line 13 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(Model.Context.RawData.Count);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" records were loaded, only the first 10 are shown here.</h4>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 14 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\r\n <h4");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Headers_DeviceSerialNumberRequired\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"error\"");
|
||||||
|
|
||||||
|
WriteLiteral(">The Device Serial Number column must be defined.</h4>\r\n\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Headers_TableContainer\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <table");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"tableData\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <thead>\r\n <tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 22 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 22 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var header in Model.Context.Header.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <th");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headerindex=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 24 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(header.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteAttribute("class", Tuple.Create(" class=\"", 984), Tuple.Create("\"", 1030)
|
||||||
|
, Tuple.Create(Tuple.Create("", 992), Tuple.Create("header", 992), true)
|
||||||
|
|
||||||
|
#line 24 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
, Tuple.Create(Tuple.Create("", 998), Tuple.Create<System.Object, System.Int32>(header.Item1.Item2.ToString()
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
, 998), false)
|
||||||
|
);
|
||||||
|
|
||||||
|
WriteLiteral(">");
|
||||||
|
|
||||||
|
|
||||||
|
#line 24 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(header.Item1.Item1);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</th>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 25 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tr>\r\n <tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 28 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 28 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var header in Model.Context.Header.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <td");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headerindex=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 30 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(header.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteAttribute("class", Tuple.Create(" class=\"", 1313), Tuple.Create("\"", 1359)
|
||||||
|
, Tuple.Create(Tuple.Create("", 1321), Tuple.Create("header", 1321), true)
|
||||||
|
|
||||||
|
#line 30 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
, Tuple.Create(Tuple.Create("", 1327), Tuple.Create<System.Object, System.Int32>(header.Item1.Item2.ToString()
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
, 1327), false)
|
||||||
|
);
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <ul");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"importHeaderType\"");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headerindex=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 31 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(header.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headertype=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 31 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(header.Item1.Item2.ToString());
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <li><a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral("><span");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"headerTypeTitle\"");
|
||||||
|
|
||||||
|
WriteLiteral(">");
|
||||||
|
|
||||||
|
|
||||||
|
#line 32 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(Model.HeaderTypes.FirstOrDefault(h => h.Item1 == header.Item1.Item2).Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</span></a>\r\n <ul>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 34 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 34 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var headerType in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <li");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headertype=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 36 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(headerType.Item1);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteLiteral("><a");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral(">");
|
||||||
|
|
||||||
|
|
||||||
|
#line 36 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(headerType.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</a></li>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 37 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </ul>\r\n </li>\r" +
|
||||||
|
"\n </ul>\r\n </td>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 42 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tr>\r\n </thead>\r\n <tbody>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 46 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 46 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var record in Model.Context.RawData.Take(10))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 49 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 49 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var field in record.Select((h, i) => Tuple.Create(h, i)))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <td");
|
||||||
|
|
||||||
|
WriteLiteral(" data-headerindex=\"");
|
||||||
|
|
||||||
|
|
||||||
|
#line 51 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(field.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\"");
|
||||||
|
|
||||||
|
WriteLiteral(">");
|
||||||
|
|
||||||
|
|
||||||
|
#line 51 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(field.Item1);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("</td>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 52 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tr>\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 54 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </tbody>\r\n </table>\r\n </div>\r\n <div");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"actionBar\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 59 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 59 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
using (Html.BeginForm(MVC.API.Device.ImportParse(Model.Context.SessionId, null)))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" <a");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Headers_Submit\"");
|
||||||
|
|
||||||
|
WriteLiteral(" href=\"#\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"button\"");
|
||||||
|
|
||||||
|
WriteLiteral(">Parse Device Import</a> \r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 62 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" </div>\r\n</div>\r\n<div");
|
||||||
|
|
||||||
|
WriteLiteral(" id=\"Devices_Import_Parsing_Dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"dialog\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Parsing devices import...\"");
|
||||||
|
|
||||||
|
WriteLiteral(">\r\n <h4><i");
|
||||||
|
|
||||||
|
WriteLiteral(" class=\"fa fa-lg fa-cog fa-spin\"");
|
||||||
|
|
||||||
|
WriteLiteral(" title=\"Please Wait\"");
|
||||||
|
|
||||||
|
WriteLiteral("></i>Parsing device import...</h4>\r\n</div>\r\n<script>\r\n $(function () {\r\n " +
|
||||||
|
" var headerTypes = {\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 71 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
|
||||||
|
#line 71 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
foreach (var h in Model.HeaderTypes)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" ");
|
||||||
|
|
||||||
|
WriteLiteral("\'");
|
||||||
|
|
||||||
|
|
||||||
|
#line 73 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(h.Item1);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\': \'");
|
||||||
|
|
||||||
|
|
||||||
|
#line 73 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
Write(h.Item2);
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral("\',");
|
||||||
|
|
||||||
|
WriteLiteral("\r\n");
|
||||||
|
|
||||||
|
|
||||||
|
#line 74 "..\..\Views\Device\ImportHeaders.cshtml"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#line default
|
||||||
|
#line hidden
|
||||||
|
WriteLiteral(" };\r\n\r\n var $Devices_Import_Headers_TableContainer = $(\'#Devices_Im" +
|
||||||
|
"port_Headers_TableContainer\');\r\n var $importHeaderTypes = $Devices_Import" +
|
||||||
|
"_Headers_TableContainer.find(\'thead\').find(\'ul.importHeaderType\');\r\n var " +
|
||||||
|
"$Devices_Import_Headers_DeviceSerialNumberRequired = $(\'#Devices_Import_Headers_" +
|
||||||
|
"DeviceSerialNumberRequired\');\r\n var $Devices_Import_Headers_Submit = $(\'#" +
|
||||||
|
"Devices_Import_Headers_Submit\');\r\n var $Devices_Import_Parsing_Dialog = n" +
|
||||||
|
"ull;\r\n\r\n function getUsedHeaders() {\r\n return $importHeaderTyp" +
|
||||||
|
"es.map(function () { return $(this).attr(\'data-headertype\'); }).filter(function " +
|
||||||
|
"() { return this != \'IgnoreColumn\' }).get();\r\n }\r\n\r\n function upda" +
|
||||||
|
"teHeaderOptions() {\r\n var usedHeaders = getUsedHeaders();\r\n " +
|
||||||
|
" var deviceSerialNumberPresent = (usedHeaders.indexOf(\'DeviceSerialNumber\') >= " +
|
||||||
|
"0);\r\n\r\n if (deviceSerialNumberPresent) {\r\n $Devices_Im" +
|
||||||
|
"port_Headers_Submit.attr(\'disabled\', null);\r\n $Devices_Import_Hea" +
|
||||||
|
"ders_DeviceSerialNumberRequired.hide();\r\n } else {\r\n $" +
|
||||||
|
"Devices_Import_Headers_DeviceSerialNumberRequired.show();\r\n $Devi" +
|
||||||
|
"ces_Import_Headers_Submit.attr(\'disabled\', \'disabled\');\r\n }\r\n\r\n " +
|
||||||
|
" $importHeaderTypes.each(function () {\r\n var $header = $(thi" +
|
||||||
|
"s);\r\n var $headerType = $header.attr(\'data-headertype\');\r\n " +
|
||||||
|
" $header.find(\'li[data-headertype]\').each(function () {\r\n " +
|
||||||
|
" var $headerOption = $(this);\r\n var $headerOptionType = $" +
|
||||||
|
"headerOption.attr(\'data-headertype\');\r\n if ($headerOptionType" +
|
||||||
|
" === $headerType) {\r\n $headerOption.removeClass(\'ui-state" +
|
||||||
|
"-disabled\');\r\n $headerOption.addClass(\'ui-state-highlight" +
|
||||||
|
"\');\r\n } else if (usedHeaders.indexOf($headerOptionType) < 0) " +
|
||||||
|
"{\r\n $headerOption.removeClass(\'ui-state-disabled ui-state" +
|
||||||
|
"-highlight\');\r\n } else {\r\n $headerOpti" +
|
||||||
|
"on.removeClass(\'ui-state-highlight\');\r\n $headerOption.add" +
|
||||||
|
"Class(\'ui-state-disabled\');\r\n }\r\n })\r\n " +
|
||||||
|
" });\r\n }\r\n\r\n function updateDataStyle(index, headerType) {\r\n " +
|
||||||
|
" $Devices_Import_Headers_TableContainer.find(\'tbody\').find(\'td[data-head" +
|
||||||
|
"erindex=\"\' + index + \'\"]\').removeClass().addClass(\'header\' + headerType);\r\n " +
|
||||||
|
" $Devices_Import_Headers_TableContainer.find(\'thead\').find(\'td[data-header" +
|
||||||
|
"index=\"\' + index + \'\"], th[data-headerindex=\"\' + index + \'\"]\').removeClass().add" +
|
||||||
|
"Class(\'header\' + headerType);\r\n }\r\n\r\n $Devices_Import_Headers_Tabl" +
|
||||||
|
"eContainer.find(\'thead\').on(\'menuselect\', \'ul.importHeaderType\', function (e, ui" +
|
||||||
|
") {\r\n var headerType = ui.item.attr(\'data-headertype\');\r\n\r\n " +
|
||||||
|
" if (headerType !== undefined) {\r\n var $this = $(this).closest(\'" +
|
||||||
|
"ul.importHeaderType\');\r\n var headerIndex = $this.attr(\'data-heade" +
|
||||||
|
"rindex\');\r\n var headerTypeName = headerTypes[headerType];\r\n " +
|
||||||
|
" $this.attr(\'data-headertype\', headerType).find(\'span.headerTypeTitle\')" +
|
||||||
|
".text(headerTypeName);\r\n updateDataStyle(headerIndex, headerType)" +
|
||||||
|
";\r\n updateHeaderOptions();\r\n }\r\n });\r\n\r\n " +
|
||||||
|
" // Add Type Options\r\n $importHeaderTypes.each(function () {\r\n " +
|
||||||
|
" var $this = $(this);\r\n var thisHeaderIndex = $this.attr(\'data-header" +
|
||||||
|
"index\');\r\n var thisHeaderType = $this.attr(\'data-headertype\');\r\n " +
|
||||||
|
" updateDataStyle(thisHeaderIndex, thisHeaderType);\r\n }).menu({ posi" +
|
||||||
|
"tion: { my: \"left top\", at: \"left bottom\" } });\r\n\r\n updateHeaderOptions()" +
|
||||||
|
";\r\n\r\n $(\'#Devices_Import_Headers_Submit\').click(function () {\r\n\r\n " +
|
||||||
|
" // Validate Device Serial Number Present\r\n var usedHeaders = getU" +
|
||||||
|
"sedHeaders();\r\n var deviceSerialNumberPresent = (usedHeaders.indexOf(" +
|
||||||
|
"\'DeviceSerialNumber\') >= 0);\r\n if (!deviceSerialNumberPresent) {\r\n " +
|
||||||
|
" updateHeaderOptions();\r\n $Devices_Import_Headers_Dev" +
|
||||||
|
"iceSerialNumberRequired.show(\'highlight\');\r\n } else {\r\n " +
|
||||||
|
" var $form = $(this).closest(\'form\');\r\n\r\n // Build Form\r\n " +
|
||||||
|
" $importHeaderTypes.each(function () {\r\n var $this = " +
|
||||||
|
"$(this);\r\n var thisHeaderIndex = $this.attr(\'data-headerindex" +
|
||||||
|
"\');\r\n var thisHeaderType = $this.attr(\'data-headertype\');\r\n\r\n" +
|
||||||
|
" $(document.createElement(\'input\')).attr({ type: \'hidden\', na" +
|
||||||
|
"me: \'Headers[\' + thisHeaderIndex + \']\', value: thisHeaderType }).appendTo($form)" +
|
||||||
|
";\r\n });\r\n\r\n // Submit Form\r\n if ($D" +
|
||||||
|
"evices_Import_Parsing_Dialog == null) {\r\n $Devices_Import_Par" +
|
||||||
|
"sing_Dialog = $(\'#Devices_Import_Parsing_Dialog\').dialog({\r\n " +
|
||||||
|
" width: 400,\r\n height: 160,\r\n r" +
|
||||||
|
"esizable: false,\r\n modal: true,\r\n " +
|
||||||
|
"autoOpen: false\r\n });\r\n }\r\n $De" +
|
||||||
|
"vices_Import_Parsing_Dialog.dialog(\'open\');\r\n $form.submit();\r\n " +
|
||||||
|
" }\r\n\r\n return false;\r\n });\r\n });\r\n</script>\r\n");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#pragma warning restore 1591
|
||||||
@@ -1,15 +1,171 @@
|
|||||||
@model Disco.Web.Models.Device.ImportReviewModel
|
@model Disco.Web.Models.Device.ImportReviewModel
|
||||||
@using Disco.BI.DeviceBI.Importing
|
@using Disco.Models.Services.Devices.Importing;
|
||||||
|
@using System.Data;
|
||||||
@{
|
@{
|
||||||
Authorization.Require(Claims.Device.Actions.Import);
|
Authorization.Require(Claims.Device.Actions.Import);
|
||||||
|
|
||||||
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices", MVC.Device.ImportExport(), string.Format("File: {0}", Model.ImportFilename));
|
ViewBag.Title = Html.ToBreadcrumb("Devices", MVC.Device.Index(), "Import Devices", MVC.Device.Import(), string.Format("File: {0}", Model.Context.Filename));
|
||||||
|
|
||||||
int importDeviceOkCount = Model.ImportDevices.Count(id => id.Errors.Count == 0);
|
|
||||||
int importDeviceNewCount = Model.ImportDevices.Count(id => id.Errors.Count == 0 && id.Device == null);
|
|
||||||
int importDeviceUpdateCount = Model.ImportDevices.Count(id => id.Errors.Count == 0 && id.Device != null);
|
|
||||||
int importDeviceErrorCount = Model.ImportDevices.Count - importDeviceOkCount;
|
|
||||||
}
|
}
|
||||||
|
<div id="Devices_Import_Review">
|
||||||
|
|
||||||
|
<h2>Review Pending Changes</h2>
|
||||||
|
|
||||||
|
<h3>Parsed @Model.Context.Records.Count Device Record@(Model.Context.Records.Count != 1 ? "s" : null)</h3>
|
||||||
|
<h4>
|
||||||
|
@Model.StatisticImportRecords of @Model.Context.Records.Count Device@(Model.Context.Records.Count != 1 ? "s" : null) are ready for import.
|
||||||
|
</h4>
|
||||||
|
@if (Model.StatisticErrorRecords > 0)
|
||||||
|
{
|
||||||
|
<h4 class="field-validation-error">
|
||||||
|
@(Model.StatisticErrorRecords) Record@(Model.StatisticErrorRecords != 1 ? "s" : null) will be skipped due to parse errors.
|
||||||
|
</h4>
|
||||||
|
}
|
||||||
|
<div id="Devices_Import_Review_Navigation">
|
||||||
|
<ul class="none">
|
||||||
|
@if (Model.StatisticErrorRecords > 0)
|
||||||
|
{<li class="actionDetached">
|
||||||
|
<input id="Devices_Import_Review_Navigation_Error" type="checkbox" checked /><label for="Devices_Import_Review_Navigation_Error">Show Errors (@(Model.StatisticErrorRecords))</label>
|
||||||
|
</li>}@if (Model.StatisticNewRecords > 0)
|
||||||
|
{<li class="actionAdded">
|
||||||
|
<input id="Devices_Import_Review_Navigation_New" type="checkbox" checked /><label for="Devices_Import_Review_Navigation_New">Show New Devices (@(Model.StatisticNewRecords))</label>
|
||||||
|
</li>}@if (Model.StatisticModifiedRecords > 0)
|
||||||
|
{<li class="actionModified">
|
||||||
|
<input id="Devices_Import_Review_Navigation_Modified" type="checkbox" checked /><label for="Devices_Import_Review_Navigation_Modified">Show Modified Devices (@(Model.StatisticModifiedRecords))</label>
|
||||||
|
</li>}@if (Model.StatisticUnmodifiedRecords > 0)
|
||||||
|
{<li class="actionUnchanged">
|
||||||
|
<input id="Devices_Import_Review_Navigation_Unchanged" type="checkbox" checked /><label for="Devices_Import_Review_Navigation_Unchanged">Show Unchanged Devices (@(Model.StatisticUnmodifiedRecords))</label>
|
||||||
|
</li>}
|
||||||
|
</ul>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$navigationContainer = $('#Devices_Import_Review_Navigation');
|
||||||
|
$tableBody = $('#Devices_Import_Review_TableContainer').find('tbody');
|
||||||
|
|
||||||
|
$navigationContainer.on('change', 'input', function () {
|
||||||
|
$tableBody.find('tr').show();
|
||||||
|
|
||||||
|
$navigationContainer.find('input').each(function () {
|
||||||
|
var $this = $(this);
|
||||||
|
var action = $this.closest('li').attr('class');
|
||||||
|
var records = $tableBody.find('tr.' + action);
|
||||||
|
if ($this.is(':checked')) {
|
||||||
|
records.show();
|
||||||
|
} else {
|
||||||
|
records.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
<div id="Devices_Import_Review_TableContainer">
|
||||||
|
<table class="tableData">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Action</th>
|
||||||
|
<th>Row</th>
|
||||||
|
@foreach (var header in Model.Context.ParsedHeaders)
|
||||||
|
{
|
||||||
|
<th>@(Model.HeaderTypes.FirstOrDefault(h => h.Item1 == header.Item2).Item2)</th>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th> </th>
|
||||||
|
@foreach (var header in Model.Context.ParsedHeaders)
|
||||||
|
{
|
||||||
|
<th>@header.Item1</th>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach (var recordEntry in Model.Context.Records.Select((r, i) => Tuple.Create(r, i)))
|
||||||
|
{
|
||||||
|
var record = recordEntry.Item1;
|
||||||
|
<tr class="action@(record.RecordAction)">
|
||||||
|
<td class="action"><i class="fa fa-fw"></i></td>
|
||||||
|
<td>@(recordEntry.Item2 + 1)</td>
|
||||||
|
@foreach (var field in record.Fields)
|
||||||
|
{
|
||||||
|
var friendlyValue = field.FriendlyValue;
|
||||||
|
<td class="header@(field.FieldType) action@(field.FieldAction.HasValue ? field.FieldAction.ToString() : "Error")" data-previousvalue="@(field.FieldAction.HasValue && field.FieldAction.Value == System.Data.EntityState.Modified ? field.FriendlyPreviousValue : null)">
|
||||||
|
@if (!field.FieldAction.HasValue)
|
||||||
|
{
|
||||||
|
<span class="errorMessage"><strong>Error:</strong> @field.ErrorMessage</span>
|
||||||
|
<i class="fa fa-exclamation-triangle fa-fw"></i>
|
||||||
|
}
|
||||||
|
@if (string.IsNullOrEmpty(friendlyValue))
|
||||||
|
{<span class="smallMessage"><None></span>}
|
||||||
|
else if (field.FieldType == DeviceImportFieldTypes.DeviceSerialNumber && field.FieldAction.HasValue && field.FieldAction.Value != EntityState.Added)
|
||||||
|
{
|
||||||
|
@Html.ActionLink(friendlyValue, MVC.Device.Show((string)field.RawParsedValue), new { target="_blank" })}
|
||||||
|
else if (field.FieldType == DeviceImportFieldTypes.AssignedUserId && field.FieldAction.HasValue && field.FieldAction.Value != EntityState.Unchanged)
|
||||||
|
{
|
||||||
|
@Html.ActionLink(friendlyValue, MVC.User.Show((string)field.RawParsedValue), new { target="_blank" })}
|
||||||
|
else
|
||||||
|
{@friendlyValue}
|
||||||
|
</td>
|
||||||
|
}
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="actionBar">
|
||||||
|
<a id="Devices_Import_Review_ChangeHeaders" href="@Url.Action(MVC.Device.ImportHeaders(Model.Context.SessionId))" class="button"><i class="fa fa-caret-left"></i>Change Import Columns</a>
|
||||||
|
@if (Model.StatisticImportRecords == 0)
|
||||||
|
{
|
||||||
|
<a id="Devices_Import_Review_Apply" href="#" class="button disabled" disabled><i class="fa fa-wrench"></i>Apply Device Import</a>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<a id="Devices_Import_Review_Apply" href="@Url.Action(MVC.API.Device.ImportApply(Model.Context.SessionId))" class="button"><i class="fa fa-wrench"></i>Apply Device Import</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
$(function () {
|
||||||
|
$Devices_Import_Review_TableContainer = $('#Devices_Import_Review_TableContainer');
|
||||||
|
|
||||||
|
$Devices_Import_Review_TableContainer.find('tbody').tooltip({
|
||||||
|
items: 'td.action, td.actionError, td.actionModified',
|
||||||
|
content: function () {
|
||||||
|
var $this = $(this);
|
||||||
|
|
||||||
|
if ($this.hasClass('action')) {
|
||||||
|
var record = $(this).closest('tr');
|
||||||
|
|
||||||
|
if (record.hasClass('actionDetached')) {
|
||||||
|
return '<strong>Error Parsing Record</strong><div>Review the record fields for details about any errors.</div><div class="smallMessage">This record will be skipped.</div>';
|
||||||
|
} else if (record.hasClass('actionUnchanged')) {
|
||||||
|
return '<strong>No Changes</strong><div>No changes were found while parsing this record.</div><div class="smallMessage">This record will be skipped.</div>';
|
||||||
|
} else if (record.hasClass('actionModified')) {
|
||||||
|
return '<strong>Pending Changes</strong><div>This record contains changes which will be applied.</div>';
|
||||||
|
} else if (record.hasClass('actionAdded')) {
|
||||||
|
return '<strong>New Record</strong><div>This record will be imported.</div>';
|
||||||
|
}
|
||||||
|
} else if ($this.hasClass('actionError')) {
|
||||||
|
return $(this).find('span.errorMessage').html();
|
||||||
|
} else if ($this.hasClass('actionModified')) {
|
||||||
|
var v = $(this).attr('data-previousvalue');
|
||||||
|
if (v) {
|
||||||
|
return '<strong>Previous Value:</strong><br />' + v;
|
||||||
|
} else {
|
||||||
|
return '<strong>Previous Value:</strong><br /><em><None></em>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
my: "left top",
|
||||||
|
at: "left bottom",
|
||||||
|
collision: "flipfit flip"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
@*
|
||||||
<div id="deviceImportReview">
|
<div id="deviceImportReview">
|
||||||
@if (Model.ImportDevices.Count > 0)
|
@if (Model.ImportDevices.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -248,4 +404,4 @@
|
|||||||
{
|
{
|
||||||
<h2>No Devices were found in this file</h2>
|
<h2>No Devices were found in this file</h2>
|
||||||
}
|
}
|
||||||
</div>
|
</div>*@
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,7 +11,7 @@
|
|||||||
<div class="actionBar">
|
<div class="actionBar">
|
||||||
@if (Authorization.Has(Claims.Device.Actions.Import))
|
@if (Authorization.Has(Claims.Device.Actions.Import))
|
||||||
{
|
{
|
||||||
@Html.ActionLinkButton("Import Devices", MVC.Device.ImportExport())
|
@Html.ActionLinkButton("Import Devices", MVC.Device.Import())
|
||||||
}
|
}
|
||||||
@if (Authorization.Has(Claims.Device.Actions.Export))
|
@if (Authorization.Has(Claims.Device.Actions.Export))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ WriteLiteral(">\r\n");
|
|||||||
#line hidden
|
#line hidden
|
||||||
|
|
||||||
#line 14 "..\..\Views\Device\Index.cshtml"
|
#line 14 "..\..\Views\Device\Index.cshtml"
|
||||||
Write(Html.ActionLinkButton("Import Devices", MVC.Device.ImportExport()));
|
Write(Html.ActionLinkButton("Import Devices", MVC.Device.Import()));
|
||||||
|
|
||||||
|
|
||||||
#line default
|
#line default
|
||||||
|
|||||||
@@ -33,6 +33,11 @@
|
|||||||
</appSettings>
|
</appSettings>
|
||||||
|
|
||||||
<system.web>
|
<system.web>
|
||||||
|
<compilation>
|
||||||
|
<assemblies>
|
||||||
|
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
</assemblies>
|
||||||
|
</compilation>
|
||||||
<httpHandlers>
|
<httpHandlers>
|
||||||
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
|
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
|
||||||
</httpHandlers>
|
</httpHandlers>
|
||||||
|
|||||||
Reference in New Issue
Block a user