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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user