Compare commits
107 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 83e9b7a832 | |||
| a3a92245ae | |||
| 045fb0b65d | |||
| 304ffd7ee1 | |||
| 8b74dbabf5 | |||
| 7f8ed7e752 | |||
| 84a4ba281f | |||
| 34842012b7 | |||
| a819d2722a | |||
| ebf78dd08d | |||
| 6186237028 | |||
| 513397779d | |||
| 815216fd73 | |||
| 8254e7ec5a | |||
| 4c3a68da30 | |||
| b64ac3b16f | |||
| d040ab094c | |||
| a0e18ef963 | |||
| 830a9c8d05 | |||
| ea51ba1f88 | |||
| 5510d34885 | |||
| be25569245 | |||
| 7af6a2220c | |||
| 4cd57f4a90 | |||
| f6fae26bc7 | |||
| 7cad69598f | |||
| 4e69253852 | |||
| 825627e345 | |||
| e9042f7666 | |||
| 6a45348bdb | |||
| f3351af9e8 | |||
| a5e38406d1 | |||
| 3c759ac4d7 | |||
| f70261aa25 | |||
| 3fdb4f1053 | |||
| 53ca13c7f4 | |||
| 185c4682f0 | |||
| 39c3bf9fc7 | |||
| c87ee6a0e7 | |||
| 4a08c8c275 | |||
| fb6067afc3 | |||
| 6b2cd47610 | |||
| 392de396df | |||
| 3cf6d5475d | |||
| 74df073b29 | |||
| 09c2a24222 | |||
| 43fc622121 | |||
| b8ec44293f | |||
| 36100bfef5 | |||
| b77bdf16f5 | |||
| 5aede7153c | |||
| 4fc6c3ca9f | |||
| d86280ae3e | |||
| 2281313966 | |||
| 740e806ef0 | |||
| f35f9d3661 | |||
| 201acc1976 | |||
| a4f4b7d0b3 | |||
| 41dc002ef8 | |||
| e984221c95 | |||
| 3238a916a2 | |||
| db73cc1a12 | |||
| b841c6b2c0 | |||
| 69091e0785 | |||
| 3d5f71aba9 | |||
| da166e5cd2 | |||
| 74775e9e3d | |||
| 96c5860080 | |||
| 6ac87633ac | |||
| 0db43d9200 | |||
| a82e039140 | |||
| bfa3bf1e94 | |||
| 5be747afbc | |||
| ed7caf8b4a | |||
| 7027b33fe2 | |||
| 68256d7abd | |||
| 2ac3a9bdd3 | |||
| a6a65c54c7 | |||
| 7bdbeb6a82 | |||
| c4cc54d316 | |||
| 3ae657f2ba | |||
| 2e7b66ee5b | |||
| 6d54f3f972 | |||
| cd31ba4a6c | |||
| 9ea0273936 | |||
| 7748f15d76 | |||
| eea71e6eb0 | |||
| 3bc8b63700 | |||
| 6bacf6e3a5 | |||
| cc4682875b | |||
| bfcbcf9da2 | |||
| ad28729a85 | |||
| 3f63281dc4 | |||
| bdb3e1e6b4 | |||
| 10394c4e39 | |||
| 2ddf4b7bd9 | |||
| 35391ad1a1 | |||
| ab553a05cb | |||
| 20263905f9 | |||
| f1ee2937cd | |||
| ec118a3395 | |||
| 551b1d3a41 | |||
| 214ecf6212 | |||
| fad8eae9f4 | |||
| 2dd3f5f9ab | |||
| 8ace60f10d | |||
| 136c371b01 |
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Microsoft.AspNet.SignalR.Utils" version="2.1.0" />
|
||||
</packages>
|
||||
@@ -15,10 +15,10 @@ namespace Disco.BI.AttachmentBI
|
||||
if (Source != null)
|
||||
{
|
||||
// GDI+ (jpg, png, gif, bmp)
|
||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
||||
SourceMimeType.Equals("image/png", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("png") ||
|
||||
SourceMimeType.Equals("image/gif", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("gif") ||
|
||||
SourceMimeType.Equals("image/bmp", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("bmp"))
|
||||
if (SourceMimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("jpg") ||
|
||||
SourceMimeType.Equals("image/png", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("png") ||
|
||||
SourceMimeType.Equals("image/gif", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("gif") ||
|
||||
SourceMimeType.Equals("image/bmp", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("bmp"))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -42,7 +42,7 @@ namespace Disco.BI.AttachmentBI
|
||||
}
|
||||
|
||||
// PDF
|
||||
if (SourceMimeType.Equals("application/pdf", StringComparison.InvariantCultureIgnoreCase) || SourceMimeType.Contains("pdf"))
|
||||
if (SourceMimeType.Equals("application/pdf", StringComparison.OrdinalIgnoreCase) || SourceMimeType.Contains("pdf"))
|
||||
{
|
||||
PdfReader pdfReader = new PdfReader(Source);
|
||||
try
|
||||
|
||||
+123
-62
@@ -1,13 +1,13 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.BI.Interop.ActiveDirectory;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.ClientServices;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Tamir.SharpSsh;
|
||||
@@ -242,7 +242,7 @@ namespace Disco.BI.DeviceBI
|
||||
EnrolmentLog.LogSessionTaskAddedDevice(sessionId, Request.DeviceSerialNumber);
|
||||
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
|
||||
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
@@ -252,7 +252,7 @@ namespace Disco.BI.DeviceBI
|
||||
RepoDevice = new Device
|
||||
{
|
||||
SerialNumber = Request.DeviceSerialNumber,
|
||||
ComputerName = Request.DeviceComputerName,
|
||||
DeviceDomainId = Request.DeviceComputerName,
|
||||
DeviceProfile = deviceProfile,
|
||||
DeviceModel = deviceModel,
|
||||
AllowUnauthenticatedEnrol = false,
|
||||
@@ -267,7 +267,7 @@ namespace Disco.BI.DeviceBI
|
||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
|
||||
if (!RepoDevice.DeviceModelId.HasValue || RepoDevice.DeviceModelId.Value == 1)
|
||||
{
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
@@ -280,7 +280,7 @@ namespace Disco.BI.DeviceBI
|
||||
{
|
||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, RepoDevice.DeviceModelId);
|
||||
}
|
||||
RepoDevice.ComputerName = Request.DeviceComputerName;
|
||||
RepoDevice.DeviceDomainId = Request.DeviceComputerName;
|
||||
if (!RepoDevice.EnrolledDate.HasValue)
|
||||
{
|
||||
RepoDevice.EnrolledDate = DateTime.Now;
|
||||
@@ -294,14 +294,14 @@ namespace Disco.BI.DeviceBI
|
||||
//if (RepoDeviceProfileContext.DistributionType == DeviceProfileConfiguration.DeviceProfileDistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne && RepoDevice.AssignedUser != null)
|
||||
{
|
||||
ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
response.DeviceComputerName = RepoDevice.ComputerName;
|
||||
response.DeviceComputerName = RepoDevice.DeviceDomainId;
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully");
|
||||
}
|
||||
catch (EnrolSafeException ex)
|
||||
@@ -323,14 +323,27 @@ namespace Disco.BI.DeviceBI
|
||||
}
|
||||
public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Models.ClientServices.Enrol Request)
|
||||
{
|
||||
ActiveDirectoryMachineAccount MachineInfo = null;
|
||||
ADMachineAccount adMachineAccount = null;
|
||||
|
||||
EnrolResponse response = new EnrolResponse();
|
||||
|
||||
AuthorizationToken authenticatedToken = null;
|
||||
bool isAuthenticated = false;
|
||||
|
||||
ADDomain domain = null;
|
||||
Lazy<ADDomainController> domainController = new Lazy<ADDomainController>(() =>
|
||||
{
|
||||
if (domain == null)
|
||||
throw new InvalidOperationException("The [domain] variable must be initialized first");
|
||||
return domain.GetAvailableDomainController(RequireWritable: true);
|
||||
});
|
||||
|
||||
string sessionId = System.Guid.NewGuid().ToString("B");
|
||||
response.SessionId = sessionId;
|
||||
|
||||
EnrolmentLog.LogSessionStarting(sessionId, Request.DeviceSerialNumber, EnrolmentTypes.Normal);
|
||||
EnrolmentLog.LogSessionDeviceInfo(sessionId, Request);
|
||||
|
||||
try
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 10, "Loading User Data");
|
||||
@@ -348,9 +361,13 @@ namespace Disco.BI.DeviceBI
|
||||
if (!authenticatedToken.Has(Claims.Device.Actions.EnrolDevices))
|
||||
{
|
||||
if (!authenticatedToken.Has(Claims.ComputerAccount))
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.Id));
|
||||
if (!authenticatedToken.User.Id.Equals(string.Format("{0}$", Request.DeviceComputerName), System.StringComparison.InvariantCultureIgnoreCase))
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.Id));
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DeviceDNSDomainName);
|
||||
|
||||
if (!authenticatedToken.User.UserId.Equals(string.Format(@"{0}\{1}$", domain.NetBiosName, Request.DeviceComputerName), System.StringComparison.OrdinalIgnoreCase))
|
||||
throw new EnrolSafeException(string.Format("Connection not correctly authenticated (SN: {0}; Auth User: {1})", Request.DeviceSerialNumber, authenticatedToken.User.UserId));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -380,10 +397,16 @@ namespace Disco.BI.DeviceBI
|
||||
System.Guid? uuidGuid = null;
|
||||
System.Guid? macAddressGuid = null;
|
||||
if (!string.IsNullOrEmpty(Request.DeviceUUID))
|
||||
uuidGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(Request.DeviceUUID);
|
||||
uuidGuid = ADMachineAccount.NetbootGUIDFromUUID(Request.DeviceUUID);
|
||||
if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress))
|
||||
macAddressGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
|
||||
MachineInfo = ActiveDirectory.GetMachineAccount(Request.DeviceComputerName, uuidGuid, macAddressGuid);
|
||||
macAddressGuid = ADMachineAccount.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress);
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DeviceDNSDomainName);
|
||||
|
||||
var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName);
|
||||
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(requestDeviceId, uuidGuid, macAddressGuid);
|
||||
}
|
||||
if (RepoDevice == null)
|
||||
{
|
||||
@@ -392,17 +415,20 @@ namespace Disco.BI.DeviceBI
|
||||
DeviceProfile deviceProfile = Database.DeviceProfiles.Find(Database.DiscoConfiguration.DeviceProfiles.DefaultDeviceProfileId);
|
||||
|
||||
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
else
|
||||
EnrolmentLog.LogSessionDevice(sessionId, Request.DeviceSerialNumber, deviceModel.Id);
|
||||
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainByName(Request.DeviceDNSDomainName);
|
||||
|
||||
RepoDevice = new Device
|
||||
{
|
||||
SerialNumber = Request.DeviceSerialNumber,
|
||||
ComputerName = Request.DeviceComputerName,
|
||||
DeviceDomainId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName),
|
||||
DeviceProfile = deviceProfile,
|
||||
DeviceModel = deviceModel,
|
||||
AllowUnauthenticatedEnrol = false,
|
||||
@@ -423,7 +449,7 @@ namespace Disco.BI.DeviceBI
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 30, "Existing Device, Updating Disco Instance");
|
||||
EnrolmentLog.LogSessionTaskUpdatingDevice(sessionId, Request.DeviceSerialNumber);
|
||||
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModel.Trim());
|
||||
var deviceModelResult = Database.DeviceModels.GetOrCreateDeviceModel(Request.DeviceManufacturer.Trim(), Request.DeviceModel.Trim(), Request.DeviceModelType.Trim());
|
||||
DeviceModel deviceModel = deviceModelResult.Item1;
|
||||
if (deviceModelResult.Item2)
|
||||
EnrolmentLog.LogSessionTaskCreatedDeviceModel(sessionId, Request.DeviceSerialNumber, deviceModelResult.Item1.Manufacturer, deviceModelResult.Item1.Model);
|
||||
@@ -442,88 +468,123 @@ namespace Disco.BI.DeviceBI
|
||||
RepoDevice.LastEnrolDate = DateTime.Now;
|
||||
}
|
||||
|
||||
if (MachineInfo == null)
|
||||
if (adMachineAccount == null)
|
||||
{
|
||||
if (isAuthenticated || RepoDevice.AllowUnauthenticatedEnrol)
|
||||
{
|
||||
if (RepoDevice.DeviceProfile.ProvisionADAccount)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, "Provisioning an Active Directory Computer Account");
|
||||
if (string.IsNullOrEmpty(RepoDevice.ComputerName) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
RepoDevice.ComputerName = RepoDevice.ComputerNameRender(Database);
|
||||
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.ComputerName);
|
||||
MachineInfo = ActiveDirectory.GetMachineAccount(RepoDevice.ComputerName);
|
||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
if (string.IsNullOrEmpty(RepoDevice.DeviceDomainId) || RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
RepoDevice.DeviceDomainId = RepoDevice.ComputerNameRender(Database, domain);
|
||||
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
EnrolmentLog.LogSessionTaskProvisioningADAccount(sessionId, RepoDevice.SerialNumber, RepoDevice.DeviceDomainId);
|
||||
adMachineAccount = domainController.Value.RetrieveADMachineAccount(RepoDevice.DeviceDomainId);
|
||||
|
||||
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
if (MachineInfo != null)
|
||||
if (adMachineAccount != null)
|
||||
{
|
||||
response.DeviceComputerName = MachineInfo.Name;
|
||||
response.DeviceDomainName = MachineInfo.Domain;
|
||||
response.DeviceComputerName = adMachineAccount.Name;
|
||||
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.DeviceComputerName = RepoDevice.ComputerName;
|
||||
response.DeviceDomainName = RepoDevice.ComputerName;
|
||||
string accountUsername;
|
||||
ADDomain accountDomain;
|
||||
ActiveDirectory.ParseDomainAccountId(RepoDevice.DeviceDomainId, out accountUsername, out accountDomain);
|
||||
|
||||
response.DeviceDomainName = accountDomain == null ? null : accountDomain.NetBiosName;
|
||||
response.DeviceComputerName = accountUsername;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RepoDevice.ComputerName = Request.DeviceComputerName;
|
||||
response.DeviceComputerName = Request.DeviceComputerName;
|
||||
response.DeviceDomainName = RepoDevice.ComputerName;
|
||||
response.DeviceDomainName = Request.DeviceDNSDomainName;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RepoDevice.ComputerName = MachineInfo.Name;
|
||||
response.DeviceComputerName = MachineInfo.Name;
|
||||
response.DeviceDomainName = MachineInfo.Domain;
|
||||
RepoDevice.DeviceDomainId = adMachineAccount.Id.Trim('$');
|
||||
response.DeviceComputerName = adMachineAccount.Name;
|
||||
response.DeviceDomainName = adMachineAccount.Domain.NetBiosName;
|
||||
|
||||
// Enforce Computer Name Convention
|
||||
if (!MachineInfo.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
if (!adMachineAccount.IsCriticalSystemObject && RepoDevice.DeviceProfile.EnforceComputerNameConvention)
|
||||
{
|
||||
var calculatedComputerName = RepoDevice.ComputerNameRender(Database);
|
||||
if (!Request.DeviceComputerName.Equals(calculatedComputerName, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException("No Organisational Unit has been set in the device profile");
|
||||
if (domain == null)
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
|
||||
string calculatedAccountUsername;
|
||||
ActiveDirectory.ParseDomainAccountId(calculatedComputerName, out calculatedAccountUsername);
|
||||
|
||||
if (!Request.DeviceComputerName.Equals(calculatedAccountUsername, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
|
||||
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
|
||||
|
||||
RepoDevice.ComputerName = calculatedComputerName;
|
||||
response.DeviceComputerName = calculatedComputerName;
|
||||
RepoDevice.DeviceDomainId = calculatedComputerName;
|
||||
response.DeviceDomainName = domain.NetBiosName;
|
||||
response.DeviceComputerName = calculatedAccountUsername;
|
||||
|
||||
// Create New Account
|
||||
response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId);
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
|
||||
response.OfflineDomainJoin = domainController.Value.OfflineDomainJoinProvision(RepoDevice.DeviceDomainId, RepoDevice.DeviceProfile.OrganisationalUnit, ref adMachineAccount, out offlineProvisionDiagnosicInfo);
|
||||
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(sessionId, offlineProvisionDiagnosicInfo);
|
||||
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Enforce Organisation Unit
|
||||
if (!MachineInfo.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
|
||||
// Enforce Organisational Unit
|
||||
if (!adMachineAccount.IsCriticalSystemObject && response.OfflineDomainJoin == null && RepoDevice.DeviceProfile.EnforceOrganisationalUnit)
|
||||
{
|
||||
var parentDistinguishedName = MachineInfo.ParentDistinguishedName();
|
||||
var parentDistinguishedName = adMachineAccount.ParentDistinguishedName;
|
||||
if (string.IsNullOrWhiteSpace(RepoDevice.DeviceProfile.OrganisationalUnit))
|
||||
throw new InvalidOperationException(string.Format("The Organisational Unit for the Device Profile '{0}' [{1}] is not set.", RepoDevice.DeviceProfile.Name, RepoDevice.DeviceProfile.Id));
|
||||
|
||||
if ((RepoDevice.DeviceProfile.OrganisationalUnit == null && parentDistinguishedName != null
|
||||
&& parentDistinguishedName.Equals("CN=Computers", StringComparison.InvariantCultureIgnoreCase)) // Null (Default) OU
|
||||
|| !parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.InvariantCultureIgnoreCase)) // Custom OU
|
||||
if (!parentDistinguishedName.Equals(RepoDevice.DeviceProfile.OrganisationalUnit, StringComparison.OrdinalIgnoreCase)) // Custom OU
|
||||
{
|
||||
string newOU = RepoDevice.DeviceProfile.OrganisationalUnit ?? "CN=Computers";
|
||||
var proposedDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
var currentDomain = ActiveDirectory.Context.GetDomainFromDistinguishedName(parentDistinguishedName);
|
||||
if (currentDomain != proposedDomain)
|
||||
throw new NotSupportedException("Unable to move the devices organisational unit when the source and destination domains are different.");
|
||||
if (domain == null)
|
||||
domain = proposedDomain;
|
||||
else if (domain != proposedDomain)
|
||||
throw new NotSupportedException("To many domains involved in this enrolment, contact support regarding your scenario.");
|
||||
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisation Unit: {0} -> {1}", parentDistinguishedName, newOU));
|
||||
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, newOU);
|
||||
MachineInfo.MoveOrganisationUnit(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
MachineInfo = ActiveDirectory.GetMachineAccount(MachineInfo.SamAccountName);
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 65, string.Format("Moving Device Organisational Unit: {0} -> {1}", parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit));
|
||||
EnrolmentLog.LogSessionTaskMovingDeviceOrganisationUnit(sessionId, parentDistinguishedName, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
adMachineAccount.MoveOrganisationalUnit(domainController.Value, RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
response.RequireReboot = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (MachineInfo != null && !MachineInfo.IsCriticalSystemObject)
|
||||
if (adMachineAccount != null && !adMachineAccount.IsCriticalSystemObject)
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 75, "Updating Active Directory Computer Account Properties");
|
||||
MachineInfo.UpdateNetbootGUID(Request.DeviceUUID, Request.DeviceLanMacAddress);
|
||||
adMachineAccount.UpdateNetbootGUID(Request.DeviceUUID, Request.DeviceLanMacAddress);
|
||||
if (RepoDevice.AssignedUser != null)
|
||||
MachineInfo.SetDescription(RepoDevice);
|
||||
adMachineAccount.SetDescription(RepoDevice);
|
||||
}
|
||||
if (RepoDevice.DeviceProfile.DistributionType == DeviceProfile.DistributionTypes.OneToOne)
|
||||
{
|
||||
@@ -534,14 +595,14 @@ namespace Disco.BI.DeviceBI
|
||||
else
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account");
|
||||
ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier);
|
||||
ADUserAccount AssignedUserInfo = ActiveDirectory.RetrieveADUserAccount(RepoDevice.AssignedUser.UserId);
|
||||
EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain.NetBiosName, AssignedUserInfo.SecurityIdentifier.ToString());
|
||||
response.AllowBootstrapperUninstall = true;
|
||||
response.DeviceAssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin;
|
||||
response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain;
|
||||
response.DeviceAssignedUserDomain = AssignedUserInfo.Domain.NetBiosName;
|
||||
response.DeviceAssignedUserName = AssignedUserInfo.DisplayName;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier;
|
||||
response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -604,4 +665,4 @@ namespace Disco.BI.DeviceBI
|
||||
return response;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
using Disco.Models.BI.Device;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.DeviceBI.Importing
|
||||
{
|
||||
public static class Export
|
||||
{
|
||||
private const string ExportHeader = "Serial Number,Device Model,Device Profile,Device Batch,Assigned User,Location,Asset Number";
|
||||
|
||||
public static MemoryStream GenerateExport(IQueryable<Device> Devices)
|
||||
{
|
||||
var devices = Devices.Select(d => new ImportDevice()
|
||||
{
|
||||
SerialNumber = d.SerialNumber,
|
||||
DeviceModelId = d.DeviceModelId,
|
||||
DeviceProfileId = d.DeviceProfileId,
|
||||
DeviceBatchId = d.DeviceBatchId,
|
||||
AssignedUserId = d.AssignedUserId,
|
||||
Location = d.Location,
|
||||
AssetNumber = d.AssetNumber
|
||||
});
|
||||
|
||||
MemoryStream exportStream = new MemoryStream();
|
||||
|
||||
StreamWriter exportWriter = new StreamWriter(exportStream);
|
||||
// Write Header
|
||||
exportWriter.WriteLine(ExportHeader);
|
||||
|
||||
foreach (var device in devices)
|
||||
device.ExportCsv(exportWriter);
|
||||
|
||||
exportWriter.Flush();
|
||||
|
||||
exportStream.Position = 0;
|
||||
return exportStream;
|
||||
}
|
||||
|
||||
private static void ExportCsv(this ImportDevice device, StreamWriter writer)
|
||||
{
|
||||
// SERIAL NUMBER
|
||||
writer.Write('"');
|
||||
writer.Write(device.SerialNumber.Replace("\"", "\"\""));
|
||||
writer.Write('"');
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// DEVICE MODEL
|
||||
if (device.DeviceModelId.HasValue)
|
||||
writer.Write(device.DeviceModelId.Value);
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// DEVICE PROFILE
|
||||
writer.Write(device.DeviceProfileId);
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// DEVICE BATCH
|
||||
if (device.DeviceBatchId.HasValue)
|
||||
writer.Write(device.DeviceBatchId.Value);
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// ASSIGNED USER
|
||||
if (device.AssignedUserId != null)
|
||||
{
|
||||
writer.Write('"');
|
||||
writer.Write(device.AssignedUserId.Replace("\"", "\"\""));
|
||||
writer.Write('"');
|
||||
}
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// LOCATION
|
||||
if (!string.IsNullOrWhiteSpace(device.Location))
|
||||
{
|
||||
writer.Write('"');
|
||||
writer.Write(device.Location.Replace("\"", "\"\""));
|
||||
writer.Write('"');
|
||||
}
|
||||
|
||||
writer.Write(',');
|
||||
|
||||
// ASSET NUMBER
|
||||
if (!string.IsNullOrWhiteSpace(device.AssetNumber))
|
||||
{
|
||||
writer.Write('"');
|
||||
writer.Write(device.AssetNumber.Replace("\"", "\"\""));
|
||||
writer.Write('"');
|
||||
}
|
||||
|
||||
writer.WriteLine();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Device;
|
||||
using Disco.Models.Repository;
|
||||
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");
|
||||
|
||||
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,76 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Search;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.BI.DeviceBI
|
||||
{
|
||||
public static class Searching
|
||||
{
|
||||
private static List<DeviceSearchResultItem> Search_SelectDeviceSearchResultItem(IQueryable<Device> Query, int? LimitCount = null)
|
||||
{
|
||||
if (LimitCount.HasValue)
|
||||
Query = Query.Take(LimitCount.Value);
|
||||
|
||||
return Query.Select(d => new DeviceSearchResultItem()
|
||||
{
|
||||
SerialNumber = d.SerialNumber,
|
||||
AssetNumber = d.AssetNumber,
|
||||
ComputerName = d.ComputerName,
|
||||
DeviceModelDescription = d.DeviceModel.Description,
|
||||
DeviceProfileDescription = d.DeviceProfile.Description,
|
||||
DecommissionedDate = d.DecommissionedDate,
|
||||
AssignedUserId = d.AssignedUserId,
|
||||
AssignedUserDisplayName = d.AssignedUser.DisplayName,
|
||||
JobCount = d.Jobs.Count()
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public static List<DeviceSearchResultItem> Search(DiscoDataContext Database, string Term, int? LimitCount = null, bool SearchDetails = false)
|
||||
{
|
||||
IQueryable<Device> query;
|
||||
|
||||
query = null;
|
||||
|
||||
if (SearchDetails)
|
||||
{
|
||||
query = Database.Devices.Where(d =>
|
||||
d.AssetNumber.Contains(Term) ||
|
||||
d.ComputerName.Contains(Term) ||
|
||||
d.SerialNumber.Contains(Term) ||
|
||||
d.Location.Contains(Term) ||
|
||||
Term.Contains(d.SerialNumber) ||
|
||||
d.DeviceDetails.Any(dd => dd.Value.Contains(Term))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = Database.Devices.Where(d =>
|
||||
d.AssetNumber.Contains(Term) ||
|
||||
d.ComputerName.Contains(Term) ||
|
||||
d.SerialNumber.Contains(Term) ||
|
||||
d.Location.Contains(Term) ||
|
||||
Term.Contains(d.SerialNumber));
|
||||
}
|
||||
|
||||
return Search_SelectDeviceSearchResultItem(query, LimitCount);
|
||||
}
|
||||
|
||||
public static List<DeviceSearchResultItem> SearchDeviceModel(DiscoDataContext Database, int DeviceModelId, int? LimitCount = null)
|
||||
{
|
||||
return Search_SelectDeviceSearchResultItem(Database.Devices.Where(d => d.DeviceModelId == DeviceModelId), LimitCount);
|
||||
}
|
||||
public static List<DeviceSearchResultItem> SearchDeviceProfile(DiscoDataContext Database, int DeviceProfileId, int? LimitCount = null)
|
||||
{
|
||||
return Search_SelectDeviceSearchResultItem(Database.Devices.Where(d => d.DeviceProfileId == DeviceProfileId), LimitCount);
|
||||
}
|
||||
public static List<DeviceSearchResultItem> SearchDeviceBatch(DiscoDataContext Database, int DeviceBatchId, int? LimitCount = null)
|
||||
{
|
||||
return Search_SelectDeviceSearchResultItem(Database.Devices.Where(d => d.DeviceBatchId == DeviceBatchId), LimitCount);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
namespace Disco.BI.DocumentTemplateBI
|
||||
{
|
||||
@@ -61,14 +62,14 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
public string DataScope { get; private set; }
|
||||
public static bool IsDocumentUniqueIdentifier(string UniqueIdentifier)
|
||||
{
|
||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.InvariantCultureIgnoreCase);
|
||||
return UniqueIdentifier.StartsWith("Disco|", System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
|
||||
{
|
||||
this.Tag = Tag;
|
||||
this.TemplateTypeId = TemplateTypeId;
|
||||
this.DataId = DataId;
|
||||
this.CreatorId = CreatorId;
|
||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(CreatorId);
|
||||
this.TimeStamp = TimeStamp;
|
||||
this.Page = Page ?? 0;
|
||||
}
|
||||
@@ -93,7 +94,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
}
|
||||
if (s.Length >= 5)
|
||||
{
|
||||
this.CreatorId = s[4];
|
||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(s[4]);
|
||||
}
|
||||
if (s.Length >= 6)
|
||||
{
|
||||
@@ -180,7 +181,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
}
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
User u = Database.Users.Find(this.DataId);
|
||||
User u = Database.Users.Find(ActiveDirectory.ParseDomainAccountId(this.DataId));
|
||||
if (u != null)
|
||||
{
|
||||
this._data = u;
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace Disco.BI.DocumentTemplateBI.Importer
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Trigger Daily @ 12:30am
|
||||
|
||||
@@ -0,0 +1,486 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
||||
{
|
||||
public class DocumentTemplateDevicesManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DocumentTemplate_{0}_Devices";
|
||||
private const string DeviceDescriptionFormat = "Devices with a {0} attachment will be added to this Active Directory group.";
|
||||
private const string DescriptionFormat = "{0}s with a {1} attachment will have any associated devices added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Related Devices Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Document Template Devices]";
|
||||
|
||||
private IDisposable repositoryAddSubscription;
|
||||
private IDisposable repositoryRemoveSubscription;
|
||||
private IDisposable deviceRenameRepositorySubscription;
|
||||
private IDisposable jobCloseRepositorySubscription;
|
||||
private IDisposable deviceAssignmentRepositorySubscription;
|
||||
private string DocumentTemplateId;
|
||||
private string DocumentTemplateDescription;
|
||||
private string DocumentTemplateScope;
|
||||
|
||||
public override string Description { get { return GetDescription(DocumentTemplateScope, DocumentTemplateDescription); } }
|
||||
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
||||
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DocumentTemplateDescription); } }
|
||||
public override bool IncludeFilterBeginDate { get { return true; } }
|
||||
|
||||
private DocumentTemplateDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DocumentTemplate DocumentTemplate)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DocumentTemplateId = DocumentTemplate.Id;
|
||||
this.DocumentTemplateDescription = DocumentTemplate.Description;
|
||||
this.DocumentTemplateScope = DocumentTemplate.Scope;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// Subscribe to changes
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
// Observe Device Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.DeviceAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((DeviceAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessDeviceAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.DeviceAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessDeviceAttachmentRemoveEvent);
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
// Observe Job Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.JobAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((JobAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessJobAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.JobAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessJobAttachmentRemoveEvent);
|
||||
// Observe Job Close/Reopen
|
||||
jobCloseRepositorySubscription = DocumentTemplateManagedGroups.JobCloseRepositoryEvents.Value
|
||||
.Subscribe(ProcessJobCloseRepositoryEvent);
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
// Observe User Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.UserAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((UserAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessUserAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.UserAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessUserAttachmentRemoveEvent);
|
||||
// Observe Device Assignments
|
||||
deviceAssignmentRepositorySubscription = DocumentTemplateManagedGroups.DeviceAssignmentRepositoryEvents.Value
|
||||
.Subscribe(ProcessDeviceAssignmentRepositoryEvent);
|
||||
break;
|
||||
}
|
||||
|
||||
// Observe Device Renaming (DeviceDomainId)
|
||||
deviceRenameRepositorySubscription = DocumentTemplateManagedGroups.DeviceRenameRepositoryEvents.Value
|
||||
.Subscribe(ProcessDeviceRenameRepositoryEvent);
|
||||
}
|
||||
|
||||
public static string GetKey(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return string.Format(KeyFormat, DocumentTemplate.Id);
|
||||
}
|
||||
private static string GetDescription(string DocumentTemplateScope, string DocumentTemplateDescription)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
return string.Format(DeviceDescriptionFormat, DocumentTemplateDescription);
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return string.Format(DescriptionFormat, DocumentTemplateScope, DocumentTemplateDescription);
|
||||
default:
|
||||
throw new ArgumentException("Unknown Document Template Scope", "Scope");
|
||||
}
|
||||
}
|
||||
public static string GetDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return GetDescription(DocumentTemplate.Scope, DocumentTemplate.Description);
|
||||
}
|
||||
public static string GetCategoryDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return CategoryDescriptionFormat;
|
||||
}
|
||||
|
||||
public static bool TryGetManagedGroup(DocumentTemplate DocumentTemplate, out DocumentTemplateDevicesManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DocumentTemplate);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DocumentTemplateDevicesManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentTemplateDevicesManagedGroup Initialize(DocumentTemplate Template)
|
||||
{
|
||||
var key = GetKey(Template);
|
||||
|
||||
if (!string.IsNullOrEmpty(Template.DevicesLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(Template.DevicesLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DocumentTemplateDevicesManagedGroup(
|
||||
key,
|
||||
config,
|
||||
Template);
|
||||
|
||||
// Add to AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.Remove(key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
return Database.Devices
|
||||
.Where(d => d.DeviceDomainId != null && d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(d => d.DeviceDomainId)
|
||||
.ToList()
|
||||
.Where(ActiveDirectory.IsValidDomainAccountId)
|
||||
.Select(id => id + "$");
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
return Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.Device.DeviceDomainId != null && j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(j => j.Device.DeviceDomainId)
|
||||
.Distinct()
|
||||
.ToList()
|
||||
.Where(ActiveDirectory.IsValidDomainAccountId)
|
||||
.Select(id => id + "$");
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return Database.Users
|
||||
.Where(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.SelectMany(u => u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue && dua.Device.DeviceDomainId != null), (u, dua) => dua.Device.DeviceDomainId)
|
||||
.ToList()
|
||||
.Where(ActiveDirectory.IsValidDomainAccountId)
|
||||
.Select(id => id + "$");
|
||||
default:
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
#region Device Scope
|
||||
private bool DeviceContainsAttachment(DiscoDataContext Database, string DeviceSerialNumber, out string DeviceAccountId)
|
||||
{
|
||||
var result = Database.Devices
|
||||
.Where(d => d.SerialNumber == DeviceSerialNumber && d.DeviceDomainId != null)
|
||||
.Select(d => new Tuple<string, bool>(d.DeviceDomainId, d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
DeviceAccountId = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ActiveDirectory.IsValidDomainAccountId(result.Item1))
|
||||
{
|
||||
DeviceAccountId = result.Item1 + "$";
|
||||
return result.Item2;
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceAccountId = result.Item1 + "$";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (DeviceAttachment)e.Entity;
|
||||
|
||||
string deviceAccountId;
|
||||
if (DeviceContainsAttachment(e.Database, attachment.DeviceSerialNumber, out deviceAccountId))
|
||||
AddMember(attachment.DeviceSerialNumber, (database) => new string[] { deviceAccountId });
|
||||
}
|
||||
private void ProcessDeviceAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, string> e)
|
||||
{
|
||||
var deviceSerialNumber = e.Item3;
|
||||
|
||||
RemoveMember(deviceSerialNumber, (database) =>
|
||||
{
|
||||
string deviceAccountId;
|
||||
if (!DeviceContainsAttachment(database, deviceSerialNumber, out deviceAccountId) && deviceAccountId != null)
|
||||
return new string[] { deviceAccountId };
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Job Scope
|
||||
private bool JobsContainAttachment(DiscoDataContext Database, int JobId, out string DeviceAccountId, out string DeviceSerialNumber)
|
||||
{
|
||||
var result = Database.Jobs
|
||||
.Where(j => j.Id == JobId && j.Device.DeviceDomainId != null)
|
||||
.Select(j => new Tuple<string, string, bool>(
|
||||
j.Device.DeviceDomainId,
|
||||
j.Device.SerialNumber,
|
||||
j.Device.Jobs.Where(dj => !dj.ClosedDate.HasValue).Any(dj => dj.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
).FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
DeviceAccountId = null;
|
||||
DeviceSerialNumber = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ActiveDirectory.IsValidDomainAccountId(result.Item1))
|
||||
{
|
||||
DeviceAccountId = result.Item1 + "$";
|
||||
DeviceSerialNumber = result.Item2;
|
||||
return result.Item3;
|
||||
}
|
||||
else
|
||||
{
|
||||
DeviceAccountId = result.Item1 + "$";
|
||||
DeviceSerialNumber = result.Item2;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessJobAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (JobAttachment)e.Entity;
|
||||
|
||||
string deviceAccountId;
|
||||
string deviceSerialNumber;
|
||||
if (JobsContainAttachment(e.Database, attachment.JobId, out deviceAccountId, out deviceSerialNumber))
|
||||
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
||||
}
|
||||
private void ProcessJobAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, int> e)
|
||||
{
|
||||
var jobId = e.Item4;
|
||||
string deviceSerialNumber = e.Item1.Jobs.Where(j => j.Id == jobId && j.DeviceSerialNumber != null).Select(j => j.DeviceSerialNumber).FirstOrDefault();
|
||||
|
||||
if (deviceSerialNumber != null)
|
||||
{
|
||||
RemoveMember(deviceSerialNumber, (database) =>
|
||||
{
|
||||
string deviceAccountId;
|
||||
if (!JobsContainAttachment(database, jobId, out deviceAccountId, out deviceSerialNumber) &&
|
||||
deviceSerialNumber != null && deviceAccountId != null)
|
||||
return new string[] { deviceAccountId };
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User Scope
|
||||
private bool DeviceUserContainAttachment(DiscoDataContext Database, string UserId, out List<Tuple<string, string>> Devices)
|
||||
{
|
||||
var result = Database.Users
|
||||
.Where(u => u.UserId == UserId)
|
||||
.Select(u => new Tuple<bool, IEnumerable<Tuple<string, string>>>(
|
||||
u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId),
|
||||
u.DeviceUserAssignments
|
||||
.Where(dua => !dua.UnassignedDate.HasValue && dua.Device.DeviceDomainId != null)
|
||||
.Select(dua => new Tuple<string, string>(dua.Device.DeviceDomainId, dua.Device.SerialNumber)))
|
||||
).FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
Devices = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Devices = result.Item2
|
||||
.Where(d => ActiveDirectory.IsValidDomainAccountId(d.Item1))
|
||||
.Select(d => Tuple.Create(d.Item1 + "$", d.Item2))
|
||||
.ToList();
|
||||
return result.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessUserAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (UserAttachment)e.Entity;
|
||||
|
||||
List<Tuple<string, string>> devices;
|
||||
if (DeviceUserContainAttachment(e.Database, attachment.UserId, out devices) && devices != null)
|
||||
devices.ForEach(d => AddMember(d.Item2, (database) => new string[] { d.Item1 }));
|
||||
}
|
||||
private void ProcessUserAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, string> e)
|
||||
{
|
||||
var userId = e.Item4;
|
||||
|
||||
RemoveMember(userId, (database) =>
|
||||
{
|
||||
List<Tuple<string, string>> devices;
|
||||
if (!DeviceUserContainAttachment(database, userId, out devices) && devices != null)
|
||||
return devices.Select(d => d.Item1);
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void ProcessDeviceRenameRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
var deviceSerialNumber = device.SerialNumber;
|
||||
var deviceAccountId = device.DeviceDomainId;
|
||||
var deviceAccountIdValid = ActiveDirectory.IsValidDomainAccountId(deviceAccountId);
|
||||
var devicePreviousAccountId = Event.GetPreviousPropertyValue<string>("DeviceDomainId");
|
||||
var devicePreviousAccountIdValid = ActiveDirectory.IsValidDomainAccountId(devicePreviousAccountId);
|
||||
|
||||
if (deviceAccountIdValid || devicePreviousAccountIdValid)
|
||||
{
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
if (DeviceContainsAttachment(e.Database, device.SerialNumber, out deviceAccountId))
|
||||
{
|
||||
if (deviceAccountIdValid)
|
||||
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId });
|
||||
if (devicePreviousAccountIdValid)
|
||||
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
||||
}
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
var jobsHaveTemplate = e.Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.DeviceSerialNumber == deviceSerialNumber)
|
||||
.Any(j => j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
||||
|
||||
if (jobsHaveTemplate)
|
||||
{
|
||||
if (deviceAccountIdValid)
|
||||
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
||||
if (devicePreviousAccountIdValid)
|
||||
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
||||
}
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
var userHasTemplate = e.Database.Devices
|
||||
.Where(d => d.SerialNumber == deviceSerialNumber)
|
||||
.Select(d => d.AssignedUser)
|
||||
.Any(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
||||
|
||||
if (userHasTemplate)
|
||||
{
|
||||
if (deviceAccountIdValid)
|
||||
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
||||
if (devicePreviousAccountIdValid)
|
||||
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessJobCloseRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var job = (Job)e.Entity;
|
||||
|
||||
if (job.DeviceSerialNumber != null)
|
||||
{
|
||||
var jobId = job.Id;
|
||||
|
||||
var relevantJob = e.Database.Jobs
|
||||
.Where(j => j.Id == jobId && j.JobAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (relevantJob)
|
||||
{
|
||||
string deviceAccountId;
|
||||
string deviceSerialNumber;
|
||||
if (JobsContainAttachment(e.Database, jobId, out deviceAccountId, out deviceSerialNumber))
|
||||
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
||||
else
|
||||
RemoveMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceAssignmentRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
var deviceSerialNumber = device.SerialNumber;
|
||||
var deviceAccountId = device.DeviceDomainId;
|
||||
|
||||
if (ActiveDirectory.IsValidDomainAccountId(deviceAccountId))
|
||||
{
|
||||
var deviceCurrentAssignedUserId = device.AssignedUserId;
|
||||
var devicePreviousAssignedUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
bool previousUserHasTemplate = false;
|
||||
bool currentUserHasTemplate = false;
|
||||
|
||||
if (devicePreviousAssignedUserId != null)
|
||||
previousUserHasTemplate = e.Database.Users
|
||||
.Where(u => u.UserId == devicePreviousAssignedUserId && u.UserAttachments.Any(ua => ua.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (deviceCurrentAssignedUserId != null)
|
||||
currentUserHasTemplate = e.Database.Users
|
||||
.Where(u => u.UserId == deviceCurrentAssignedUserId && u.UserAttachments.Any(ua => ua.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (!previousUserHasTemplate && currentUserHasTemplate)
|
||||
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
||||
else if (previousUserHasTemplate && !currentUserHasTemplate)
|
||||
RemoveMember(deviceSerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositoryAddSubscription != null)
|
||||
repositoryAddSubscription.Dispose();
|
||||
|
||||
if (repositoryRemoveSubscription != null)
|
||||
repositoryRemoveSubscription.Dispose();
|
||||
|
||||
if (deviceRenameRepositorySubscription != null)
|
||||
deviceRenameRepositorySubscription.Dispose();
|
||||
|
||||
if (jobCloseRepositorySubscription != null)
|
||||
jobCloseRepositorySubscription.Dispose();
|
||||
|
||||
if (deviceAssignmentRepositorySubscription != null)
|
||||
deviceAssignmentRepositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
|
||||
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
||||
{
|
||||
public static class DocumentTemplateManagedGroups
|
||||
{
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceAttachmentAddRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> JobAttachmentAddRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> UserAttachmentAddRepositoryEvents;
|
||||
|
||||
internal static Lazy<Subject<Tuple<DiscoDataContext, int, string, string>>> DeviceAttachmentRemoveEvents;
|
||||
internal static Lazy<Subject<Tuple<DiscoDataContext, int, string, int>>> JobAttachmentRemoveEvents;
|
||||
internal static Lazy<Subject<Tuple<DiscoDataContext, int, string, string>>> UserAttachmentRemoveEvents;
|
||||
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceRenameRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> JobCloseRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceAssignmentRepositoryEvents;
|
||||
|
||||
static DocumentTemplateManagedGroups()
|
||||
{
|
||||
DeviceAttachmentAddRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(DeviceAttachment) &&
|
||||
((DeviceAttachment)e.Entity).DocumentTemplateId != null &&
|
||||
e.EventType == RepositoryMonitorEventType.Added
|
||||
));
|
||||
JobAttachmentAddRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(JobAttachment) &&
|
||||
((JobAttachment)e.Entity).DocumentTemplateId != null &&
|
||||
e.EventType == RepositoryMonitorEventType.Added
|
||||
));
|
||||
UserAttachmentAddRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(UserAttachment) &&
|
||||
((UserAttachment)e.Entity).DocumentTemplateId != null &&
|
||||
e.EventType == RepositoryMonitorEventType.Added
|
||||
));
|
||||
|
||||
DeviceAttachmentRemoveEvents =
|
||||
new Lazy<Subject<Tuple<DiscoDataContext, int, string, string>>>(() => new Subject<Tuple<DiscoDataContext, int, string, string>>());
|
||||
JobAttachmentRemoveEvents =
|
||||
new Lazy<Subject<Tuple<DiscoDataContext, int, string, int>>>(() => new Subject<Tuple<DiscoDataContext, int, string, int>>());
|
||||
UserAttachmentRemoveEvents =
|
||||
new Lazy<Subject<Tuple<DiscoDataContext, int, string, string>>>(() => new Subject<Tuple<DiscoDataContext, int, string, string>>());
|
||||
|
||||
DeviceRenameRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("DeviceDomainId")
|
||||
));
|
||||
JobCloseRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(Job) &&
|
||||
(((Job)e.Entity).DeviceSerialNumber != null || ((Job)e.Entity).UserId != null) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("ClosedDate")
|
||||
));
|
||||
DeviceAssignmentRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("AssignedUserId")
|
||||
));
|
||||
}
|
||||
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
Database.DocumentTemplates
|
||||
.Where(dp => dp.DevicesLinkedGroup != null || dp.UsersLinkedGroup != null)
|
||||
.ToList()
|
||||
.ForEach(dp =>
|
||||
{
|
||||
DocumentTemplateDevicesManagedGroup.Initialize(dp);
|
||||
DocumentTemplateUsersManagedGroup.Initialize(dp);
|
||||
});
|
||||
}
|
||||
|
||||
public static void TriggerDeviceAttachmentDeleted(DiscoDataContext Database, int AttachmentId, string DocumentTemplateId, string DeviceSerialNumber)
|
||||
{
|
||||
if (DocumentTemplateId != null)
|
||||
DeviceAttachmentRemoveEvents.Value.OnNext(Tuple.Create(Database, AttachmentId, DocumentTemplateId, DeviceSerialNumber));
|
||||
}
|
||||
|
||||
public static void TriggerJobAttachmentDeleted(DiscoDataContext Database, int AttachmentId, string DocumentTemplateId, int JobId)
|
||||
{
|
||||
if (DocumentTemplateId != null)
|
||||
JobAttachmentRemoveEvents.Value.OnNext(Tuple.Create(Database, AttachmentId, DocumentTemplateId, JobId));
|
||||
}
|
||||
|
||||
public static void TriggerUserAttachmentDeleted(DiscoDataContext Database, int AttachmentId, string DocumentTemplateId, string UserId)
|
||||
{
|
||||
if (DocumentTemplateId != null)
|
||||
UserAttachmentRemoveEvents.Value.OnNext(Tuple.Create(Database, AttachmentId, DocumentTemplateId, UserId));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
||||
{
|
||||
public class DocumentTemplateUsersManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DocumentTemplate_{0}_Users";
|
||||
private const string UserDescriptionFormat = "Users with a {0} attachment will be added to this Active Directory group.";
|
||||
private const string DescriptionFormat = "{0}s with a {1} attachment will have any associated users added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Related Users Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Document Template Users]";
|
||||
|
||||
private IDisposable repositoryAddSubscription;
|
||||
private IDisposable repositoryRemoveSubscription;
|
||||
private IDisposable jobCloseRepositorySubscription;
|
||||
private IDisposable deviceAssignmentRepositorySubscription;
|
||||
private string DocumentTemplateId;
|
||||
private string DocumentTemplateDescription;
|
||||
private string DocumentTemplateScope;
|
||||
|
||||
public override string Description { get { return GetDescription(DocumentTemplateScope, DocumentTemplateDescription); } }
|
||||
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
||||
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DocumentTemplateDescription); } }
|
||||
public override bool IncludeFilterBeginDate { get { return true; } }
|
||||
|
||||
private DocumentTemplateUsersManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DocumentTemplate DocumentTemplate)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DocumentTemplateId = DocumentTemplate.Id;
|
||||
this.DocumentTemplateDescription = DocumentTemplate.Description;
|
||||
this.DocumentTemplateScope = DocumentTemplate.Scope;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// Subscribe to changes
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
// Observe Device Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.DeviceAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((DeviceAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessDeviceAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.DeviceAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessDeviceAttachmentRemoveEvent);
|
||||
// Observe Device Assignments
|
||||
deviceAssignmentRepositorySubscription = DocumentTemplateManagedGroups.DeviceAssignmentRepositoryEvents.Value
|
||||
.Subscribe(ProcessDeviceAssignmentRepositoryEvent);
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
// Observe Job Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.UserAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((JobAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessJobAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.JobAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessJobAttachmentRemoveEvent);
|
||||
// Observe Job Close/Reopen
|
||||
jobCloseRepositorySubscription = DocumentTemplateManagedGroups.JobCloseRepositoryEvents.Value
|
||||
.Subscribe(ProcessJobCloseRepositoryEvent);
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
// Observe User Attachments
|
||||
repositoryAddSubscription = DocumentTemplateManagedGroups.UserAttachmentAddRepositoryEvents.Value
|
||||
.Where(e => ((UserAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessUserAttachmentAddEvent);
|
||||
repositoryRemoveSubscription = DocumentTemplateManagedGroups.UserAttachmentRemoveEvents.Value
|
||||
.Where(e => e.Item3 == DocumentTemplateId)
|
||||
.Subscribe(ProcessUserAttachmentRemoveEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetKey(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return string.Format(KeyFormat, DocumentTemplate.Id);
|
||||
}
|
||||
private static string GetDescription(string DocumentTemplateScope, string DocumentTemplateDescription)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
return string.Format(DescriptionFormat, DocumentTemplateScope, DocumentTemplateDescription);
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return string.Format(UserDescriptionFormat, DocumentTemplateDescription);
|
||||
default:
|
||||
throw new ArgumentException("Unknown Document Template Scope", "Scope");
|
||||
}
|
||||
}
|
||||
public static string GetDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return GetDescription(DocumentTemplate.Scope, DocumentTemplate.Description);
|
||||
}
|
||||
public static string GetCategoryDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return CategoryDescriptionFormat;
|
||||
}
|
||||
|
||||
public static bool TryGetManagedGroup(DocumentTemplate DocumentTemplate, out DocumentTemplateUsersManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DocumentTemplate);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DocumentTemplateUsersManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentTemplateUsersManagedGroup Initialize(DocumentTemplate Template)
|
||||
{
|
||||
var key = GetKey(Template);
|
||||
|
||||
if (!string.IsNullOrEmpty(Template.UsersLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(Template.UsersLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DocumentTemplateUsersManagedGroup(
|
||||
key,
|
||||
config,
|
||||
Template);
|
||||
|
||||
// Add to AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.Remove(key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
return Database.Devices
|
||||
.Where(d => d.AssignedUserId != null && d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(d => d.AssignedUserId);
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
return Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.UserId != null && j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(j => j.UserId)
|
||||
.Distinct();
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return Database.Users
|
||||
.Where(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(u => u.UserId);
|
||||
default:
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
#region Device Scope
|
||||
private bool DeviceContainsAttachment(DiscoDataContext Database, string DeviceSerialNumber, out string UserId)
|
||||
{
|
||||
var result = Database.Devices
|
||||
.Where(d => d.SerialNumber == DeviceSerialNumber && d.AssignedUser != null)
|
||||
.Select(d => new Tuple<string, bool>(d.AssignedUserId, d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
UserId = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserId = result.Item1;
|
||||
return result.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (DeviceAttachment)e.Entity;
|
||||
|
||||
string userId;
|
||||
if (DeviceContainsAttachment(e.Database, attachment.DeviceSerialNumber, out userId) && userId != null)
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
private void ProcessDeviceAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, string> e)
|
||||
{
|
||||
var deviceSerialNumber = e.Item4;
|
||||
string userId = e.Item1.Devices.Where(d => d.SerialNumber == deviceSerialNumber && d.AssignedUserId != null).Select(j => j.AssignedUserId).FirstOrDefault();
|
||||
|
||||
if (userId != null)
|
||||
{
|
||||
RemoveMember(userId, (database) =>
|
||||
{
|
||||
if (DeviceContainsAttachment(database, deviceSerialNumber, out userId) && userId != null)
|
||||
return new string[] { userId };
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Job Scope
|
||||
private bool JobsContainAttachment(DiscoDataContext Database, int JobId, out string UserId)
|
||||
{
|
||||
var result = Database.Jobs
|
||||
.Where(j => j.Id == JobId && j.UserId != null)
|
||||
.Select(j => new Tuple<string, bool>(
|
||||
j.UserId,
|
||||
j.User.Jobs.Where(uj => !uj.ClosedDate.HasValue).Any(uj => uj.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
).FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
UserId = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserId = result.Item1;
|
||||
return result.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessJobAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (JobAttachment)e.Entity;
|
||||
|
||||
string userId;
|
||||
if (JobsContainAttachment(e.Database, attachment.JobId, out userId) && userId != null)
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
private void ProcessJobAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, int> e)
|
||||
{
|
||||
var jobId = e.Item4;
|
||||
string userId = e.Item1.Jobs.Where(j => j.Id == jobId && j.UserId != null).Select(j => j.UserId).FirstOrDefault();
|
||||
|
||||
if (userId != null)
|
||||
{
|
||||
RemoveMember(userId, (database) =>
|
||||
{
|
||||
if (JobsContainAttachment(database, jobId, out userId) && userId != null)
|
||||
return new string[] { userId };
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User Scope
|
||||
private bool UserContainAttachment(DiscoDataContext Database, string UserId)
|
||||
{
|
||||
var result = Database.Users
|
||||
.Where(u => u.UserId == UserId)
|
||||
.Any(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ProcessUserAttachmentAddEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (UserAttachment)e.Entity;
|
||||
var userId = attachment.UserId;
|
||||
|
||||
if (UserContainAttachment(e.Database, userId) && userId != null)
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
private void ProcessUserAttachmentRemoveEvent(Tuple<DiscoDataContext, int, string, string> e)
|
||||
{
|
||||
var userId = e.Item4;
|
||||
|
||||
RemoveMember(userId, (database) =>
|
||||
{
|
||||
if (!UserContainAttachment(database, userId))
|
||||
return new string[] { userId };
|
||||
else
|
||||
return null;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void ProcessJobCloseRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var job = (Job)e.Entity;
|
||||
|
||||
if (job.UserId != null)
|
||||
{
|
||||
var jobId = job.Id;
|
||||
|
||||
var relevantJob = e.Database.Jobs
|
||||
.Where(j => j.Id == jobId && j.JobAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (relevantJob)
|
||||
{
|
||||
string userId;
|
||||
if (JobsContainAttachment(e.Database, jobId, out userId))
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
else
|
||||
RemoveMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceAssignmentRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
var deviceSerialNumber = device.SerialNumber;
|
||||
|
||||
var relevantDevice = Event.Database.Devices
|
||||
.Where(d => d.SerialNumber == deviceSerialNumber && d.DeviceAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (relevantDevice)
|
||||
{
|
||||
var deviceCurrentAssignedUserId = device.AssignedUserId;
|
||||
var devicePreviousAssignedUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
if (devicePreviousAssignedUserId != null)
|
||||
RemoveMember(devicePreviousAssignedUserId, (database) => new string[] { devicePreviousAssignedUserId });
|
||||
|
||||
if (deviceCurrentAssignedUserId != null)
|
||||
AddMember(deviceCurrentAssignedUserId, (database) => new string[] { deviceCurrentAssignedUserId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositoryAddSubscription != null)
|
||||
repositoryAddSubscription.Dispose();
|
||||
|
||||
if (repositoryRemoveSubscription != null)
|
||||
repositoryRemoveSubscription.Dispose();
|
||||
|
||||
if (jobCloseRepositorySubscription != null)
|
||||
jobCloseRepositorySubscription.Dispose();
|
||||
|
||||
if (deviceAssignmentRepositorySubscription != null)
|
||||
deviceAssignmentRepositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using Disco.BI.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions
|
||||
{
|
||||
@@ -16,10 +13,11 @@ namespace Disco.BI.Expressions
|
||||
public override string TaskName { get { return "Expression Cache - Preload Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Run in Background 1 Second after Scheduled (on App Startup)
|
||||
// Run in Background 5 Second after Scheduled (on App Startup)
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(new DateTimeOffset(DateTime.Now).AddSeconds(5));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
@@ -36,8 +34,6 @@ namespace Disco.BI.Expressions
|
||||
documentTemplate.FilterExpressionFromCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.BI.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
@@ -14,7 +12,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
var adMachineAccount = Device.ActiveDirectoryAccount(PropertyName);
|
||||
if (adMachineAccount != null)
|
||||
return adMachineAccount.GetPropertyValue(PropertyName, Index);
|
||||
return adMachineAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
}
|
||||
public static FileImageExpressionResult JobAttachmentFirstImage(Job Job, DiscoDataContext Database)
|
||||
{
|
||||
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
|
||||
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
|
||||
if (attachment != null)
|
||||
{
|
||||
var filename = attachment.RepositoryFilename(Database);
|
||||
@@ -39,7 +39,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
}
|
||||
public static FileImageExpressionResult JobAttachmentLastImage(Job Job, DiscoDataContext Database)
|
||||
{
|
||||
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase));
|
||||
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
|
||||
if (attachment != null)
|
||||
{
|
||||
var filename = attachment.RepositoryFilename(Database);
|
||||
@@ -52,7 +52,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
if (JobAttachment == null)
|
||||
throw new ArgumentNullException("JobAttachment");
|
||||
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException("Invalid Image MimeType for Attachment");
|
||||
|
||||
var filename = JobAttachment.RepositoryFilename(Database);
|
||||
@@ -65,7 +65,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
if (Job.JobAttachments == null)
|
||||
throw new ArgumentException("Job.JobAttachments is null", "Job");
|
||||
|
||||
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
if (attachments.Count > 0)
|
||||
{
|
||||
@@ -81,7 +81,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
if (JobAttachments == null)
|
||||
throw new ArgumentNullException("JobAttachments");
|
||||
|
||||
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.InvariantCultureIgnoreCase)).ToList();
|
||||
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
|
||||
|
||||
if (attachments.Count > 0)
|
||||
{
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.BI.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
public static class UserExt
|
||||
{
|
||||
#region Active Directory Extensions
|
||||
public static object GetActiveDirectoryObjectValue(User User, string PropertyName, int Index = 0)
|
||||
{
|
||||
var adUserAccount = User.ActiveDirectoryAccount(PropertyName);
|
||||
if (adUserAccount != null)
|
||||
return adUserAccount.GetPropertyValue(PropertyName, Index);
|
||||
return adUserAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
@@ -47,5 +46,29 @@ namespace Disco.BI.Expressions.Extensions
|
||||
return intValue;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Authorization Testing Extensions
|
||||
public static bool HasAuthorization(User User, string Claim)
|
||||
{
|
||||
var authorization = UserService.GetAuthorization(User.UserId);
|
||||
|
||||
return authorization.Has(Claim);
|
||||
}
|
||||
|
||||
public static bool HasAuthorizationAll(User User, params string[] Claims)
|
||||
{
|
||||
var authorization = UserService.GetAuthorization(User.UserId);
|
||||
|
||||
return authorization.HasAll(Claims);
|
||||
}
|
||||
|
||||
public static bool HasAuthorizationAny(User User, params string[] Claims)
|
||||
{
|
||||
var authorization = UserService.GetAuthorization(User.UserId);
|
||||
|
||||
return authorization.HasAny(Claims);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
@@ -29,8 +30,14 @@ namespace Disco.BI.Extensions
|
||||
if (!da.CanDelete())
|
||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
||||
|
||||
var attachmentId = da.Id;
|
||||
var documentTemplateId = da.DocumentTemplateId;
|
||||
var deviceSerialNumber = da.DeviceSerialNumber;
|
||||
|
||||
da.RepositoryDelete(Database);
|
||||
Database.DeviceAttachments.Remove(da);
|
||||
|
||||
DocumentTemplateManagedGroups.TriggerDeviceAttachmentDeleted(Database, attachmentId, documentTemplateId, deviceSerialNumber);
|
||||
}
|
||||
public static bool CanDelete(this JobAttachment ja)
|
||||
{
|
||||
@@ -48,8 +55,14 @@ namespace Disco.BI.Extensions
|
||||
if (!ja.CanDelete())
|
||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
||||
|
||||
var attachmentId = ja.Id;
|
||||
var documentTemplateId = ja.DocumentTemplateId;
|
||||
var jobId = ja.JobId;
|
||||
|
||||
ja.RepositoryDelete(Database);
|
||||
Database.JobAttachments.Remove(ja);
|
||||
|
||||
DocumentTemplateManagedGroups.TriggerJobAttachmentDeleted(Database, attachmentId, documentTemplateId, jobId);
|
||||
}
|
||||
public static bool CanDelete(this UserAttachment ua)
|
||||
{
|
||||
@@ -67,8 +80,14 @@ namespace Disco.BI.Extensions
|
||||
if (!ua.CanDelete())
|
||||
throw new InvalidOperationException("Deletion of Attachment is Denied");
|
||||
|
||||
var attachmentId = ua.Id;
|
||||
var documentTemplateId = ua.DocumentTemplateId;
|
||||
var userId = ua.UserId;
|
||||
|
||||
ua.RepositoryDelete(Database);
|
||||
Database.UserAttachments.Remove(ua);
|
||||
|
||||
DocumentTemplateManagedGroups.TriggerUserAttachmentDeleted(Database, attachmentId, documentTemplateId, userId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Disco.BI.Extensions
|
||||
|
||||
if (documentTemplate == null)
|
||||
{
|
||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.DataId, UniqueIdentifier.TimeStamp);
|
||||
filename = string.Format("{0}_{1:yyyyMMdd-HHmmss}.pdf", UniqueIdentifier.DataId.Replace('\\', '_'), UniqueIdentifier.TimeStamp);
|
||||
comments = string.Format("Uploaded: {0:s}", UniqueIdentifier.TimeStamp);
|
||||
}
|
||||
else
|
||||
@@ -68,7 +68,7 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
public static string RepositoryFilename(this UserAttachment ua, DiscoDataContext Database)
|
||||
{
|
||||
return Path.Combine(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_file", ua.UserId, ua.Id));
|
||||
return Path.Combine(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_file", ua.UserId.Replace('\\', '_'), ua.Id));
|
||||
}
|
||||
|
||||
private static string RepositoryThumbnailFilenameInternal(string DirectoryPath, string Filename)
|
||||
@@ -85,7 +85,7 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
public static string RepositoryThumbnailFilename(this UserAttachment ua, DiscoDataContext Database)
|
||||
{
|
||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_thumb.jpg", ua.UserId, ua.Id));
|
||||
return RepositoryThumbnailFilenameInternal(DataStore.CreateLocation(Database, "UserAttachments", ua.Timestamp), string.Format("{0}_{1}_thumb.jpg", ua.UserId.Replace('\\', '_'), ua.Id));
|
||||
}
|
||||
|
||||
public static void RepositoryDelete(this DeviceAttachment da, DiscoDataContext Database)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Authorization;
|
||||
using Disco.Models.Services.Authorization;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Disco.BI.Extensions
|
||||
|
||||
WhoAmIResponse response = new WhoAmIResponse()
|
||||
{
|
||||
Username = token.User.Id,
|
||||
Username = token.User.UserId,
|
||||
DisplayName = token.User.DisplayName,
|
||||
Type = token.Has(Claims.ComputerAccount) ? "Computer Account" : "User Account"
|
||||
};
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.BI.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
@@ -19,7 +17,7 @@ namespace Disco.BI.Extensions
|
||||
|
||||
public static bool CanCreateJob(this Device d)
|
||||
{
|
||||
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Create))
|
||||
if (!JobActionExtensions.CanCreate())
|
||||
return false;
|
||||
|
||||
return !d.IsDecommissioned();
|
||||
@@ -81,7 +79,7 @@ namespace Disco.BI.Extensions
|
||||
|
||||
return true;
|
||||
}
|
||||
public static void OnDecommission(this Device d, Disco.Models.Repository.Device.DecommissionReasons Reason)
|
||||
public static void OnDecommission(this Device d, Disco.Models.Repository.DecommissionReasons Reason)
|
||||
{
|
||||
if (!d.CanDecommission())
|
||||
throw new InvalidOperationException("Decommission of Device is Denied");
|
||||
@@ -90,7 +88,7 @@ namespace Disco.BI.Extensions
|
||||
d.DecommissionReason = Reason;
|
||||
|
||||
// Disable AD Account
|
||||
if (d.ComputerName != null)
|
||||
if (d.DeviceDomainId != null)
|
||||
{
|
||||
var adAccount = d.ActiveDirectoryAccount();
|
||||
if (adAccount != null && !adAccount.IsCriticalSystemObject)
|
||||
@@ -117,7 +115,7 @@ namespace Disco.BI.Extensions
|
||||
d.DecommissionReason = null;
|
||||
|
||||
// Enable AD Account
|
||||
if (d.ComputerName != null)
|
||||
if (d.DeviceDomainId != null)
|
||||
{
|
||||
var adAccount = d.ActiveDirectoryAccount();
|
||||
if (adAccount != null && !adAccount.IsCriticalSystemObject)
|
||||
@@ -157,10 +155,10 @@ namespace Disco.BI.Extensions
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = UserService.CurrentUser.Id,
|
||||
TechUserId = UserService.CurrentUser.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("Device Deleted{0}{0}Serial Number: {1}{0}Computer Name: {2}{0}Model: {3}{0}Profile: {4}",
|
||||
Environment.NewLine, d.SerialNumber, d.ComputerName, d.DeviceModel, d.DeviceProfile)
|
||||
Environment.NewLine, d.SerialNumber, d.DeviceDomainId, d.DeviceModel, d.DeviceProfile)
|
||||
};
|
||||
Database.JobLogs.Add(jobLog);
|
||||
}
|
||||
|
||||
@@ -10,13 +10,6 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class DeviceDetailExtensions
|
||||
{
|
||||
|
||||
#region Scope Declaration
|
||||
|
||||
public const string ScopeHardware = "Hardware";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
private static string GetDetail(this IEnumerable<DeviceDetail> details, string Scope, string Key)
|
||||
{
|
||||
@@ -73,65 +66,97 @@ namespace Disco.BI.Extensions
|
||||
detail.Value = Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region LanMacAddress
|
||||
public const string KeyLanMacAddress = "LanMacAddress";
|
||||
/// <summary>
|
||||
/// Gets the LanMacAddress Device Detail Value
|
||||
/// </summary>
|
||||
/// <returns>The LanMacAddress or null</returns>
|
||||
public static string LanMacAddress(this IEnumerable<DeviceDetail> details)
|
||||
{
|
||||
return details.GetDetail(ScopeHardware, KeyLanMacAddress);
|
||||
return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyLanMacAddress);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the LanMacAddress Device Detail Value
|
||||
/// </summary>
|
||||
public static void LanMacAddress(this IEnumerable<DeviceDetail> details, Device device, string LanMacAddress)
|
||||
{
|
||||
device.SetDetail(ScopeHardware, KeyLanMacAddress, LanMacAddress);
|
||||
}
|
||||
device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyLanMacAddress, LanMacAddress);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region WLanMacAddress
|
||||
public const string KeyWLanMacAddress = "WLanMacAddress";
|
||||
/// <summary>
|
||||
/// Gets the WLanMacAddress Device Detail Value
|
||||
/// </summary>
|
||||
/// <returns>The WLanMacAddress or null</returns>
|
||||
public static string WLanMacAddress(this IEnumerable<DeviceDetail> details)
|
||||
{
|
||||
return details.GetDetail(ScopeHardware, KeyWLanMacAddress);
|
||||
return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyWLanMacAddress);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the WLanMacAddress Device Detail Value
|
||||
/// </summary>
|
||||
public static void WLanMacAddress(this IEnumerable<DeviceDetail> details, Device device, string WLanMacAddress)
|
||||
{
|
||||
device.SetDetail(ScopeHardware, KeyWLanMacAddress, WLanMacAddress);
|
||||
}
|
||||
device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyWLanMacAddress, WLanMacAddress);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ACAdapter
|
||||
public const string KeyACAdapter = "ACAdapter";
|
||||
/// <summary>
|
||||
/// Gets the ACAdapter Device Detail Value
|
||||
/// </summary>
|
||||
/// <returns>The ACAdapter or null</returns>
|
||||
public static string ACAdapter(this IEnumerable<DeviceDetail> details)
|
||||
{
|
||||
return details.GetDetail(ScopeHardware, KeyACAdapter);
|
||||
return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyACAdapter);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the ACAdapter Device Detail Value
|
||||
/// </summary>
|
||||
public static void ACAdapter(this IEnumerable<DeviceDetail> details, Device device, string ACAdapter)
|
||||
{
|
||||
device.SetDetail(ScopeHardware, KeyACAdapter, ACAdapter);
|
||||
device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyACAdapter, ACAdapter);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Battery
|
||||
/// <summary>
|
||||
/// Gets the Battery Device Detail Value
|
||||
/// </summary>
|
||||
/// <returns>The Battery or null</returns>
|
||||
public static string Battery(this IEnumerable<DeviceDetail> details)
|
||||
{
|
||||
return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyBattery);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the Battery Device Detail Value
|
||||
/// </summary>
|
||||
public static void Battery(this IEnumerable<DeviceDetail> details, Device device, string Battery)
|
||||
{
|
||||
device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyBattery, Battery);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Keyboard
|
||||
/// <summary>
|
||||
/// Gets the Keyboard Device Detail Value
|
||||
/// </summary>
|
||||
/// <returns>The Keyboard or null</returns>
|
||||
public static string Keyboard(this IEnumerable<DeviceDetail> details)
|
||||
{
|
||||
return details.GetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyKeyboard);
|
||||
}
|
||||
/// <summary>
|
||||
/// Sets the Keyboard Device Detail Value
|
||||
/// </summary>
|
||||
public static void Keyboard(this IEnumerable<DeviceDetail> details, Device device, string Keyboard)
|
||||
{
|
||||
device.SetDetail(DeviceDetail.ScopeHardware, DeviceDetail.HardwareKeyKeyboard, Keyboard);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Linq;
|
||||
using Disco.BI.Interop.ActiveDirectory;
|
||||
using Disco.Data.Configuration;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
@@ -7,17 +6,20 @@ using Disco.Models.Repository;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.IO;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class DeviceExtensions
|
||||
{
|
||||
|
||||
public static string ComputerNameRender(this Device device, DiscoDataContext Database)
|
||||
public static string ComputerNameRender(this Device device, DiscoDataContext Database, ADDomain Domain)
|
||||
{
|
||||
if (Domain == null)
|
||||
throw new ArgumentNullException("Domain");
|
||||
|
||||
DeviceProfile deviceProfile = device.DeviceProfile;
|
||||
Expressions.Expression computerNameTemplateExpression = null;
|
||||
computerNameTemplateExpression = Expressions.ExpressionCache.GetValue(DeviceProfileExtensions.ComputerNameExpressionCacheModule, deviceProfile.Id.ToString(), () =>
|
||||
@@ -40,7 +42,8 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
throw new System.InvalidOperationException("The rendered computer name would be invalid or longer than 24 characters");
|
||||
}
|
||||
return rendered.ToString();
|
||||
|
||||
return string.Format(@"{0}\{1}", Domain.NetBiosName, rendered);
|
||||
}
|
||||
public static System.Collections.Generic.List<DocumentTemplate> AvailableDocumentTemplates(this Device d, DiscoDataContext Database, User User, System.DateTime TimeStamp)
|
||||
{
|
||||
@@ -52,18 +55,18 @@ namespace Disco.BI.Extensions
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
||||
{
|
||||
return ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device);
|
||||
return Disco.Services.Interop.ActiveDirectory.ADNetworkLogonDatesUpdateTask.UpdateLastNetworkLogonDate(Device);
|
||||
}
|
||||
|
||||
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
DeviceAttachment da = new DeviceAttachment()
|
||||
{
|
||||
DeviceSerialNumber = Device.SerialNumber,
|
||||
TechUserId = CreatorUser.Id,
|
||||
TechUserId = CreatorUser.UserId,
|
||||
Filename = Filename,
|
||||
MimeType = MimeType,
|
||||
Timestamp = DateTime.Now,
|
||||
@@ -139,7 +142,7 @@ namespace Disco.BI.Extensions
|
||||
Database.Devices.Add(d2);
|
||||
if (!string.IsNullOrEmpty(d.AssignedUserId))
|
||||
{
|
||||
User u = UserService.GetUser(d.AssignedUserId, Database, true);
|
||||
User u = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(d.AssignedUserId), Database, true);
|
||||
d2.AssignDevice(Database, u);
|
||||
}
|
||||
|
||||
@@ -160,12 +163,12 @@ namespace Disco.BI.Extensions
|
||||
newDua = new DeviceUserAssignment()
|
||||
{
|
||||
DeviceSerialNumber = d.SerialNumber,
|
||||
AssignedUserId = u.Id,
|
||||
AssignedUserId = u.UserId,
|
||||
AssignedDate = DateTime.Now
|
||||
};
|
||||
Database.DeviceUserAssignments.Add(newDua);
|
||||
|
||||
d.AssignedUserId = u.Id;
|
||||
d.AssignedUserId = u.UserId;
|
||||
d.AssignedUser = u;
|
||||
}
|
||||
else
|
||||
@@ -174,9 +177,9 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
|
||||
// Update AD Account
|
||||
if (!string.IsNullOrEmpty(d.ComputerName) && d.ComputerName.Length <= 24)
|
||||
if (!string.IsNullOrEmpty(d.DeviceDomainId))
|
||||
{
|
||||
var adMachineAccount = Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(d.ComputerName);
|
||||
var adMachineAccount = ActiveDirectory.RetrieveADMachineAccount(d.DeviceDomainId);
|
||||
if (adMachineAccount != null)
|
||||
{
|
||||
adMachineAccount.SetDescription(d);
|
||||
@@ -186,36 +189,36 @@ namespace Disco.BI.Extensions
|
||||
return newDua;
|
||||
}
|
||||
|
||||
public static ActiveDirectoryMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
||||
public static ADMachineAccount ActiveDirectoryAccount(this Device Device, params string[] AdditionalProperties)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Device.ComputerName))
|
||||
return Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(Device.ComputerName, AdditionalProperties: AdditionalProperties);
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId))
|
||||
return ActiveDirectory.RetrieveADMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string ReasonMessage(this Disco.Models.Repository.Device.DecommissionReasons r)
|
||||
public static string ReasonMessage(this Disco.Models.Repository.DecommissionReasons r)
|
||||
{
|
||||
switch (r)
|
||||
{
|
||||
case Device.DecommissionReasons.EndOfLife:
|
||||
case DecommissionReasons.EndOfLife:
|
||||
return "End of Life";
|
||||
case Device.DecommissionReasons.Sold:
|
||||
case DecommissionReasons.Sold:
|
||||
return "Sold";
|
||||
case Device.DecommissionReasons.Stolen:
|
||||
case DecommissionReasons.Stolen:
|
||||
return "Stolen";
|
||||
case Device.DecommissionReasons.Lost:
|
||||
case DecommissionReasons.Lost:
|
||||
return "Lost";
|
||||
case Device.DecommissionReasons.Damaged:
|
||||
case DecommissionReasons.Damaged:
|
||||
return "Damaged";
|
||||
case Device.DecommissionReasons.Donated:
|
||||
case DecommissionReasons.Donated:
|
||||
return "Donated";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReasonMessage(this Disco.Models.Repository.Device.DecommissionReasons? r)
|
||||
public static string ReasonMessage(this Disco.Models.Repository.DecommissionReasons? r)
|
||||
{
|
||||
if (!r.HasValue)
|
||||
return "Not Decommissioned";
|
||||
@@ -223,6 +226,17 @@ namespace Disco.BI.Extensions
|
||||
return r.Value.ReasonMessage();
|
||||
}
|
||||
|
||||
public static string StatusCode(this Device Device)
|
||||
{
|
||||
if (Device.DecommissionedDate.HasValue)
|
||||
return "Decommissioned";
|
||||
|
||||
if (!Device.EnrolledDate.HasValue)
|
||||
return "NotEnrolled";
|
||||
|
||||
return "Active";
|
||||
}
|
||||
|
||||
public static string Status(this Device Device)
|
||||
{
|
||||
if (Device.DecommissionedDate.HasValue)
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Disco.BI.Extensions
|
||||
if (!(Data is User))
|
||||
throw new ArgumentException("This Document Template is configured for Users only", "Data");
|
||||
User d3 = (User)Data;
|
||||
return d3.Id;
|
||||
return d3.UserId;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid Document Template Scope");
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class JobActionExtensions
|
||||
{
|
||||
#region Create
|
||||
public static bool CanCreate()
|
||||
{
|
||||
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Create))
|
||||
return false;
|
||||
|
||||
if (!UserService.CurrentAuthorization.HasAny(Claims.Job.Types.CreateHMisc, Claims.Job.Types.CreateHNWar, Claims.Job.Types.CreateHWar, Claims.Job.Types.CreateSApp, Claims.Job.Types.CreateSImg, Claims.Job.Types.CreateSOS, Claims.Job.Types.CreateUMgmt))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Device Held
|
||||
public static bool CanDeviceHeld(this Job j)
|
||||
@@ -29,7 +41,7 @@ namespace Disco.BI.Extensions
|
||||
throw new InvalidOperationException("Holding Device was Denied");
|
||||
|
||||
j.DeviceHeld = DateTime.Now;
|
||||
j.DeviceHeldTechUserId = Technician.Id;
|
||||
j.DeviceHeldTechUserId = Technician.UserId;
|
||||
j.DeviceReadyForReturn = null;
|
||||
j.DeviceReadyForReturnTechUserId = null;
|
||||
j.DeviceReturnedDate = null;
|
||||
@@ -52,7 +64,7 @@ namespace Disco.BI.Extensions
|
||||
throw new InvalidOperationException("Device Ready for Return was Denied");
|
||||
|
||||
j.DeviceReadyForReturn = DateTime.Now;
|
||||
j.DeviceReadyForReturnTechUserId = Technician.Id;
|
||||
j.DeviceReadyForReturnTechUserId = Technician.UserId;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -71,7 +83,7 @@ namespace Disco.BI.Extensions
|
||||
throw new InvalidOperationException("Device Return was Denied");
|
||||
|
||||
j.DeviceReturnedDate = DateTime.Now;
|
||||
j.DeviceReturnedTechUserId = Technician.Id;
|
||||
j.DeviceReturnedTechUserId = Technician.UserId;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -94,7 +106,7 @@ namespace Disco.BI.Extensions
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = Technician.Id,
|
||||
TechUserId = Technician.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("Waiting on User Action{0}Reason: {1}", Environment.NewLine, Reason)
|
||||
};
|
||||
@@ -121,7 +133,7 @@ namespace Disco.BI.Extensions
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = Technician.Id,
|
||||
TechUserId = Technician.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("User Action Resolved{0}Resolution: {1}", Environment.NewLine, Resolution)
|
||||
};
|
||||
@@ -138,7 +150,7 @@ namespace Disco.BI.Extensions
|
||||
return !j.ClosedDate.HasValue &&
|
||||
(j.DeviceSerialNumber != null) &&
|
||||
j.JobTypeId == JobType.JobTypeIds.HWar &&
|
||||
string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference);
|
||||
!j.JobMetaWarranty.ExternalLoggedDate.HasValue;
|
||||
}
|
||||
public static void OnLogWarranty(this Job j, DiscoDataContext Database, string FaultDescription, PluginFeatureManifest WarrantyProviderDefinition, OrganisationAddress Address, User TechUser, Dictionary<string, string> WarrantyProviderProperties)
|
||||
{
|
||||
@@ -166,7 +178,7 @@ namespace Disco.BI.Extensions
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = TechUser.Id,
|
||||
TechUserId = TechUser.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("Warranty Claim Submitted{0}{0}Provider: {1}{0}Repair Address: {2}{0}Provider Reference: {3}{0}{0}{4}", Environment.NewLine, WarrantyProvider.Manifest.Name, Address.Name, providerRef, FaultDescription)
|
||||
};
|
||||
@@ -210,7 +222,7 @@ namespace Disco.BI.Extensions
|
||||
var jobComponents = new List<DeviceComponent>();
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (!component.DeviceModelId.HasValue)
|
||||
if (component.JobSubTypes.Count == 0)
|
||||
{
|
||||
jobComponents.Add(component);
|
||||
}
|
||||
@@ -236,7 +248,7 @@ namespace Disco.BI.Extensions
|
||||
Database.JobComponents.Add(new JobComponent()
|
||||
{
|
||||
Job = j,
|
||||
TechUserId = techUser.Id,
|
||||
TechUserId = techUser.UserId,
|
||||
Cost = component.Cost,
|
||||
Description = component.Description
|
||||
});
|
||||
@@ -246,7 +258,7 @@ namespace Disco.BI.Extensions
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = techUser.Id,
|
||||
TechUserId = techUser.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("Job Type Converted{0}From: {1}{0}To: {2}", Environment.NewLine, Database.JobTypes.Find(JobType.JobTypeIds.HWar), Database.JobTypes.Find(JobType.JobTypeIds.HNWar))
|
||||
};
|
||||
@@ -290,7 +302,7 @@ namespace Disco.BI.Extensions
|
||||
var techUser = UserService.CurrentUser;
|
||||
|
||||
j.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
|
||||
j.JobMetaInsurance.ClaimFormSentUserId = techUser.Id;
|
||||
j.JobMetaInsurance.ClaimFormSentUserId = techUser.UserId;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -338,20 +350,56 @@ namespace Disco.BI.Extensions
|
||||
#endregion
|
||||
|
||||
#region Close
|
||||
public static bool CanClose(this Job j)
|
||||
public static void OnCloseNormally(this Job j, User Technician)
|
||||
{
|
||||
if (!j.CanCloseNormally())
|
||||
throw new InvalidOperationException("Close was Denied");
|
||||
|
||||
j.ClosedDate = DateTime.Now;
|
||||
j.ClosedTechUserId = Technician.UserId;
|
||||
}
|
||||
|
||||
private static bool CanCloseNever(this Job j, JobQueueJob IgnoreJobQueueJob = null)
|
||||
{
|
||||
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Close))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
if (j.ClosedDate.HasValue)
|
||||
return false; // Job already Closed
|
||||
return true; // Job already Closed
|
||||
|
||||
if (j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue)
|
||||
return false; // Device not returned to User
|
||||
return true; // Device not returned to User
|
||||
|
||||
if (j.WaitingForUserAction.HasValue)
|
||||
return false; // Job waiting on User Action
|
||||
return true; // Job waiting on User Action
|
||||
|
||||
if (j.JobQueues != null)
|
||||
{
|
||||
if (IgnoreJobQueueJob == null)
|
||||
{
|
||||
if (j.JobQueues.Any(jqj => !jqj.RemovedDate.HasValue))
|
||||
return true; // Job associated with a Job Queue
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j.JobQueues.Any(jqj => jqj.Id != IgnoreJobQueueJob.Id && !jqj.RemovedDate.HasValue))
|
||||
return true; // Job associated with a Job Queue
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanCloseNormally(this Job j)
|
||||
{
|
||||
if (j.CanCloseNever())
|
||||
return false;
|
||||
|
||||
return j.CanCloseNormallyInternal();
|
||||
}
|
||||
|
||||
private static bool CanCloseNormallyInternal(this Job j)
|
||||
{
|
||||
switch (j.JobTypeId)
|
||||
{
|
||||
case JobType.JobTypeIds.HWar:
|
||||
@@ -374,36 +422,27 @@ namespace Disco.BI.Extensions
|
||||
|
||||
return true;
|
||||
}
|
||||
public static void OnClose(this Job j, User Technician)
|
||||
{
|
||||
if (!j.CanClose())
|
||||
throw new InvalidOperationException("Close was Denied");
|
||||
|
||||
j.ClosedDate = DateTime.Now;
|
||||
j.ClosedTechUserId = Technician.Id;
|
||||
public static bool CanCloseJobNormallyAfterRemoved(this JobQueueJob jqj)
|
||||
{
|
||||
if (jqj.Job.CanCloseNever(jqj))
|
||||
return false;
|
||||
|
||||
return jqj.Job.CanCloseNormallyInternal();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Force Close
|
||||
public static bool CanForceClose(this Job j)
|
||||
public static bool CanCloseForced(this Job j)
|
||||
{
|
||||
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.ForceClose))
|
||||
return false;
|
||||
|
||||
var canCloseNormally = j.CanClose();
|
||||
|
||||
if (canCloseNormally)
|
||||
if (j.CanCloseNever())
|
||||
return false;
|
||||
|
||||
// Check for Override
|
||||
if (j.ClosedDate.HasValue)
|
||||
return false; // Job already Closed
|
||||
|
||||
if (j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue)
|
||||
return false; // Device not returned to User
|
||||
|
||||
if (j.WaitingForUserAction.HasValue)
|
||||
return false; // Job waiting on User Action
|
||||
if (j.CanCloseNormally())
|
||||
return false;
|
||||
|
||||
switch (j.JobTypeId)
|
||||
{
|
||||
@@ -427,23 +466,23 @@ namespace Disco.BI.Extensions
|
||||
|
||||
return false;
|
||||
}
|
||||
public static void OnForceClose(this Job j, DiscoDataContext Database, User Technician, string Reason)
|
||||
public static void OnCloseForced(this Job j, DiscoDataContext Database, User Technician, string Reason)
|
||||
{
|
||||
if (!j.CanForceClose())
|
||||
if (!j.CanCloseForced())
|
||||
throw new InvalidOperationException("Force Close was Denied");
|
||||
|
||||
// Write Log
|
||||
JobLog jobLog = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = Technician.Id,
|
||||
TechUserId = Technician.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = string.Format("Job Forcibly Closed{0}Reason: {1}", Environment.NewLine, Reason)
|
||||
};
|
||||
Database.JobLogs.Add(jobLog);
|
||||
|
||||
j.ClosedDate = DateTime.Now;
|
||||
j.ClosedTechUserId = Technician.Id;
|
||||
j.ClosedTechUserId = Technician.UserId;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -488,6 +527,11 @@ namespace Disco.BI.Extensions
|
||||
Database.JobComponents.Remove(jc);
|
||||
j.JobComponents.Clear();
|
||||
|
||||
// Job Queue Jobs
|
||||
foreach (var jqj in j.JobQueues.ToArray())
|
||||
Database.JobQueueJobs.Remove(jqj);
|
||||
j.JobQueues.Clear();
|
||||
|
||||
// Job Logs
|
||||
foreach (var jl in j.JobLogs.ToArray())
|
||||
Database.JobLogs.Remove(jl);
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.IO;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using Disco.Services.Plugins;
|
||||
using Disco.Models.BI.Job;
|
||||
using Disco.Services.Authorization;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
@@ -15,13 +16,13 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static JobAttachment CreateAttachment(this Job Job, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
JobAttachment ja = new JobAttachment()
|
||||
{
|
||||
JobId = Job.Id,
|
||||
TechUserId = CreatorUser.Id,
|
||||
TechUserId = CreatorUser.UserId,
|
||||
Filename = Filename,
|
||||
MimeType = MimeType,
|
||||
Timestamp = DateTime.Now,
|
||||
@@ -44,108 +45,6 @@ namespace Disco.BI.Extensions
|
||||
return ja;
|
||||
}
|
||||
|
||||
public static Tuple<string, string> Status(this Job j)
|
||||
{
|
||||
var statusId = j.CalculateStatusId();
|
||||
return new Tuple<string, string>(statusId, JobBI.Utilities.JobStatusDescription(statusId, j));
|
||||
}
|
||||
|
||||
public static JobTableModel.JobTableItemModelIncludeStatus ToJobTableItemModelIncludeStatus(this Job j)
|
||||
{
|
||||
var i = new JobTableModel.JobTableItemModelIncludeStatus()
|
||||
{
|
||||
Id = j.Id,
|
||||
OpenedDate = j.OpenedDate,
|
||||
ClosedDate = j.ClosedDate,
|
||||
TypeId = j.JobTypeId,
|
||||
TypeDescription = j.JobType.Description,
|
||||
Location = j.DeviceHeldLocation,
|
||||
|
||||
WaitingForUserAction = j.WaitingForUserAction,
|
||||
DeviceReadyForReturn = j.DeviceReadyForReturn,
|
||||
DeviceHeld = j.DeviceHeld,
|
||||
DeviceReturnedDate = j.DeviceReturnedDate
|
||||
};
|
||||
|
||||
if (j.Device != null)
|
||||
{
|
||||
i.DeviceSerialNumber = j.DeviceSerialNumber;
|
||||
i.DeviceModelDescription = j.Device.DeviceModel.Description;
|
||||
i.DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress;
|
||||
|
||||
if (j.JobMetaWarranty != null)
|
||||
{
|
||||
i.JobMetaWarranty_ExternalReference = j.JobMetaWarranty.ExternalReference;
|
||||
i.JobMetaWarranty_ExternalCompletedDate = j.JobMetaWarranty.ExternalCompletedDate;
|
||||
i.JobMetaWarranty_ExternalName = j.JobMetaWarranty.ExternalName;
|
||||
}
|
||||
if (j.JobMetaNonWarranty != null)
|
||||
{
|
||||
i.JobMetaNonWarranty_RepairerLoggedDate = j.JobMetaNonWarranty.RepairerLoggedDate;
|
||||
i.JobMetaNonWarranty_RepairerCompletedDate = j.JobMetaNonWarranty.RepairerCompletedDate;
|
||||
i.JobMetaNonWarranty_AccountingChargeAddedDate = j.JobMetaNonWarranty.AccountingChargeAddedDate;
|
||||
i.JobMetaNonWarranty_AccountingChargePaidDate = j.JobMetaNonWarranty.AccountingChargePaidDate;
|
||||
i.JobMetaNonWarranty_AccountingChargeRequiredDate = j.JobMetaNonWarranty.AccountingChargeRequiredDate;
|
||||
i.JobMetaNonWarranty_IsInsuranceClaim = j.JobMetaNonWarranty.IsInsuranceClaim;
|
||||
i.JobMetaNonWarranty_RepairerName = j.JobMetaNonWarranty.RepairerName;
|
||||
if (j.JobMetaInsurance != null)
|
||||
{
|
||||
i.JobMetaInsurance_ClaimFormSentDate = j.JobMetaInsurance.ClaimFormSentDate;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (j.User != null)
|
||||
{
|
||||
i.UserId = j.UserId;
|
||||
i.UserDisplayName = j.User.DisplayName;
|
||||
}
|
||||
if (j.OpenedTechUser != null)
|
||||
{
|
||||
i.OpenedTechUserId = j.OpenedTechUserId;
|
||||
i.OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public static string CalculateStatusId(this Job j)
|
||||
{
|
||||
return j.ToJobTableItemModelIncludeStatus().CalculateStatusId();
|
||||
}
|
||||
|
||||
public static string CalculateStatusId(this JobTableModel.JobTableItemModelIncludeStatus j)
|
||||
{
|
||||
if (j.ClosedDate.HasValue)
|
||||
return Job.JobStatusIds.Closed;
|
||||
|
||||
if (j.TypeId == JobType.JobTypeIds.HWar)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(j.JobMetaWarranty_ExternalReference) && !j.JobMetaWarranty_ExternalCompletedDate.HasValue)
|
||||
return Job.JobStatusIds.AwaitingWarrantyRepair; // Job Logged - but not marked as completed
|
||||
}
|
||||
|
||||
if (j.TypeId == JobType.JobTypeIds.HNWar)
|
||||
{
|
||||
if (j.JobMetaNonWarranty_RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty_RepairerCompletedDate.HasValue)
|
||||
return Job.JobStatusIds.AwaitingRepairs; // Repairs logged - but not complete
|
||||
if (j.JobMetaNonWarranty_AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty_AccountingChargePaidDate.HasValue)
|
||||
return Job.JobStatusIds.AwaitingAccountingPayment; // Accounting Charge Added, but not paid
|
||||
if (j.JobMetaNonWarranty_AccountingChargeRequiredDate.HasValue && (!j.JobMetaNonWarranty_AccountingChargePaidDate.HasValue || !j.JobMetaNonWarranty_AccountingChargeAddedDate.HasValue))
|
||||
return Job.JobStatusIds.AwaitingAccountingCharge; // Accounting Charge Required, but not added or paid
|
||||
if (j.JobMetaNonWarranty_RepairerLoggedDate.HasValue && j.JobMetaNonWarranty_IsInsuranceClaim.Value && !j.JobMetaInsurance_ClaimFormSentDate.HasValue)
|
||||
return Job.JobStatusIds.AwaitingInsuranceProcessing; // Is insurance claim, but no Claim Form Sent
|
||||
}
|
||||
|
||||
if (j.WaitingForUserAction.HasValue)
|
||||
return Job.JobStatusIds.AwaitingUserAction; // Awaiting for User
|
||||
|
||||
if (j.DeviceReadyForReturn.HasValue && !j.DeviceReturnedDate.HasValue)
|
||||
return Job.JobStatusIds.AwaitingDeviceReturn; // Device not returned to User
|
||||
|
||||
return Job.JobStatusIds.Open;
|
||||
}
|
||||
|
||||
public static List<DocumentTemplate> AvailableDocumentTemplates(this Job j, DiscoDataContext Database, User User, DateTime TimeStamp)
|
||||
{
|
||||
var dts = Database.DocumentTemplates.Include("JobSubTypes")
|
||||
@@ -249,7 +148,7 @@ namespace Disco.BI.Extensions
|
||||
Database.JobLogs.Add(new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = TechUser.Id,
|
||||
TechUserId = TechUser.UserId,
|
||||
Timestamp = DateTime.Now,
|
||||
Comments = logBuilder.ToString()
|
||||
});
|
||||
@@ -278,12 +177,12 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
foreach (var c in addedComponents)
|
||||
{
|
||||
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.InvariantCultureIgnoreCase)))
|
||||
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.OrdinalIgnoreCase)))
|
||||
{ // Job Component with matching Description doesn't exist.
|
||||
Database.JobComponents.Add(new JobComponent()
|
||||
{
|
||||
Job = j,
|
||||
TechUserId = TechUser.Id,
|
||||
TechUserId = TechUser.UserId,
|
||||
Cost = c.Cost,
|
||||
Description = c.Description
|
||||
});
|
||||
@@ -292,5 +191,42 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
private static List<string> FilterCreatableTypePermissions(AuthorizationToken Authorization)
|
||||
{
|
||||
if (!Authorization.HasAll(Claims.Job.Types.CreateHMisc, Claims.Job.Types.CreateHNWar, Claims.Job.Types.CreateHWar, Claims.Job.Types.CreateSApp, Claims.Job.Types.CreateSImg, Claims.Job.Types.CreateSOS, Claims.Job.Types.CreateUMgmt))
|
||||
{
|
||||
// Must Filter
|
||||
List<string> allowedTypes = new List<string>(6);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateHMisc))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HMisc);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateHNWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HNWar);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateHWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HWar);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateSApp))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SApp);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateSImg))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SImg);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateSOS))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SOS);
|
||||
if (Authorization.Has(Claims.Job.Types.CreateUMgmt))
|
||||
allowedTypes.Add(JobType.JobTypeIds.UMgmt);
|
||||
|
||||
return allowedTypes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IQueryable<JobType> FilterCreatableTypePermissions(this IQueryable<JobType> JobTypes, AuthorizationToken Authorization)
|
||||
{
|
||||
var allowedTypes = FilterCreatableTypePermissions(Authorization);
|
||||
|
||||
if (allowedTypes != null)
|
||||
{
|
||||
return JobTypes.Where(jt => allowedTypes.Contains(jt.Id));
|
||||
}
|
||||
|
||||
return JobTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Jobs.JobQueues;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class JobQueueActionExtensions
|
||||
{
|
||||
|
||||
#region Edit Sla
|
||||
public static bool CanEditSla(this JobQueueJob jqj)
|
||||
{
|
||||
if (jqj.RemovedDate.HasValue)
|
||||
return false;
|
||||
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnySLA))
|
||||
{
|
||||
// Can edit ANY queue
|
||||
return true;
|
||||
}
|
||||
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnSLA))
|
||||
{
|
||||
// Can edit from OWN queue
|
||||
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static void OnEditSla(this JobQueueJob jqj, DateTime? SlaExpiresDate)
|
||||
{
|
||||
if (!jqj.CanEditSla())
|
||||
throw new InvalidOperationException("Editing job SLA for this queue is denied");
|
||||
|
||||
if (SlaExpiresDate.HasValue && jqj.AddedDate > SlaExpiresDate.Value)
|
||||
throw new ArgumentException("The SLA Expires Date must be greater than the Added Date", "SLAExpiresDate");
|
||||
|
||||
jqj.SLAExpiresDate = SlaExpiresDate;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Edit Priority
|
||||
public static bool CanEditPriority(this JobQueueJob jqj)
|
||||
{
|
||||
if (jqj.RemovedDate.HasValue)
|
||||
return false;
|
||||
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnyPriority))
|
||||
{
|
||||
// Can edit ANY queue
|
||||
return true;
|
||||
}
|
||||
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnPriority))
|
||||
{
|
||||
// Can edit from OWN queue
|
||||
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static void OnEditPriority(this JobQueueJob jqj, JobQueuePriority Priority)
|
||||
{
|
||||
if (!jqj.CanEditPriority())
|
||||
throw new InvalidOperationException("Editing job priority for this queue is denied");
|
||||
|
||||
jqj.Priority = Priority;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Edit Comments
|
||||
private static bool CanEditComments(this JobQueueJob jqj)
|
||||
{
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnyComments))
|
||||
{
|
||||
// Can edit ANY queue
|
||||
return true;
|
||||
}
|
||||
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnComments))
|
||||
{
|
||||
// Can edit from OWN queue
|
||||
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static bool CanEditAddedComment(this JobQueueJob jqj)
|
||||
{
|
||||
return jqj.CanEditComments();
|
||||
}
|
||||
public static bool CanEditRemovedComment(this JobQueueJob jqj)
|
||||
{
|
||||
if (!jqj.RemovedDate.HasValue)
|
||||
return false;
|
||||
|
||||
return jqj.CanEditComments();
|
||||
}
|
||||
public static void OnEditAddedComment(this JobQueueJob jqj, string AddedComment)
|
||||
{
|
||||
if (!jqj.CanEditAddedComment())
|
||||
throw new InvalidOperationException("Editing job added comments for this queue is denied");
|
||||
|
||||
jqj.AddedComment = string.IsNullOrWhiteSpace(AddedComment) ? null : AddedComment.Trim();
|
||||
}
|
||||
public static void OnEditRemovedComment(this JobQueueJob jqj, string RemovedComment)
|
||||
{
|
||||
if (!jqj.CanEditRemovedComment())
|
||||
throw new InvalidOperationException("Editing job removed comments for this queue is denied");
|
||||
|
||||
jqj.RemovedComment = string.IsNullOrWhiteSpace(RemovedComment) ? null : RemovedComment.Trim();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
public static bool CanRemove(this JobQueueJob jqj)
|
||||
{
|
||||
if (jqj.RemovedDate.HasValue)
|
||||
return false;
|
||||
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveAnyQueues))
|
||||
{
|
||||
// Can remove from ANY queue
|
||||
return true;
|
||||
}
|
||||
else if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveOwnQueues))
|
||||
{
|
||||
// Can remove from OWN queue
|
||||
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public static void OnRemove(this JobQueueJob jqj, User Technician, string Comment)
|
||||
{
|
||||
if (!jqj.CanRemove())
|
||||
throw new InvalidOperationException("Removing job from queue is denied");
|
||||
|
||||
jqj.RemovedDate = DateTime.Now;
|
||||
jqj.RemovedUserId = Technician.UserId;
|
||||
jqj.RemovedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
public static bool CanAddQueues(this Job j)
|
||||
{
|
||||
// Job Closed?
|
||||
if (j.ClosedDate.HasValue)
|
||||
return false;
|
||||
|
||||
if (UserService.CurrentAuthorization.HasAny(Claims.Job.Actions.AddAnyQueues, Claims.Job.Actions.AddOwnQueues))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
public static bool CanAddQueue(this Job j, JobQueue jq)
|
||||
{
|
||||
// Shortcut
|
||||
if (!j.CanAddQueues())
|
||||
return false;
|
||||
|
||||
// Already in Queue?
|
||||
if (j.JobQueues.Any(jjq => !jjq.RemovedDate.HasValue && jjq.JobQueueId == jq.Id))
|
||||
return false;
|
||||
|
||||
// Can add ANY queue
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.AddAnyQueues))
|
||||
return true;
|
||||
|
||||
// Can add OWN queue
|
||||
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.AddOwnQueues))
|
||||
{
|
||||
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jq.Id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public static JobQueueJob OnAddQueue(this Job j, DiscoDataContext Database, JobQueue jq, User Technician, string Comment, DateTime? SLAExpires, JobQueuePriority Priority)
|
||||
{
|
||||
if (!j.CanAddQueue(jq))
|
||||
throw new InvalidOperationException("Adding job to queue is denied");
|
||||
|
||||
if (SLAExpires.HasValue && SLAExpires.Value < DateTime.Now)
|
||||
throw new ArgumentException("The SLA Date must be greater than the current time", "SLAExpires");
|
||||
|
||||
var jqj = new JobQueueJob()
|
||||
{
|
||||
JobQueueId = jq.Id,
|
||||
JobId = j.Id,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
AddedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(),
|
||||
SLAExpiresDate = SLAExpires,
|
||||
Priority = Priority
|
||||
};
|
||||
|
||||
Database.JobQueueJobs.Add(jqj);
|
||||
return jqj;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Job;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Authorization;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class JobTableExtensions
|
||||
{
|
||||
private static List<string> FilterAllowedTypes(AuthorizationToken Authorization)
|
||||
{
|
||||
if (!Authorization.HasAll(Claims.Job.Types.ShowHMisc, Claims.Job.Types.ShowHNWar, Claims.Job.Types.ShowHWar, Claims.Job.Types.ShowSApp, Claims.Job.Types.ShowSImg, Claims.Job.Types.ShowSOS, Claims.Job.Types.ShowUMgmt))
|
||||
{
|
||||
// Must Filter
|
||||
List<string> allowedTypes = new List<string>(6);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowHMisc))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HMisc);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowHNWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HNWar);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowHWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HWar);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowSApp))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SApp);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowSImg))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SImg);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowSOS))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SOS);
|
||||
if (Authorization.Has(Claims.Job.Types.ShowUMgmt))
|
||||
allowedTypes.Add(JobType.JobTypeIds.UMgmt);
|
||||
|
||||
return allowedTypes;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IQueryable<Job> FilterPermissions(this JobTableModel model, IQueryable<Job> Jobs, AuthorizationToken Authorization)
|
||||
{
|
||||
var allowedTypes = FilterAllowedTypes(Authorization);
|
||||
|
||||
if (allowedTypes != null)
|
||||
{
|
||||
return Jobs.Where(j => allowedTypes.Contains(j.JobTypeId));
|
||||
}
|
||||
|
||||
return Jobs;
|
||||
}
|
||||
|
||||
public static List<JobTableModel.JobTableItemModel> PermissionsFiltered(this List<JobTableModel.JobTableItemModel> Items, AuthorizationToken Authorization)
|
||||
{
|
||||
if (Items != null && Items.Count > 0)
|
||||
{
|
||||
var allowedTypes = FilterAllowedTypes(Authorization);
|
||||
|
||||
if (allowedTypes != null)
|
||||
{
|
||||
return Items.Where(j => allowedTypes.Contains(j.TypeId)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
return Items;
|
||||
}
|
||||
|
||||
public static List<JobTableModel.JobTableItemModel> DetermineItems(this JobTableModel model, DiscoDataContext Database, IQueryable<Job> Jobs)
|
||||
{
|
||||
List<JobTableModel.JobTableItemModel> items;
|
||||
|
||||
// Permissions
|
||||
var auth = UserService.CurrentAuthorization;
|
||||
if (!auth.HasAll(Claims.Job.Types.ShowHMisc, Claims.Job.Types.ShowHNWar, Claims.Job.Types.ShowHWar, Claims.Job.Types.ShowSApp, Claims.Job.Types.ShowSImg, Claims.Job.Types.ShowSOS, Claims.Job.Types.ShowUMgmt))
|
||||
{
|
||||
// Must Filter
|
||||
List<string> allowedTypes = new List<string>(6);
|
||||
if (auth.Has(Claims.Job.Types.ShowHMisc))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HMisc);
|
||||
if (auth.Has(Claims.Job.Types.ShowHNWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HNWar);
|
||||
if (auth.Has(Claims.Job.Types.ShowHWar))
|
||||
allowedTypes.Add(JobType.JobTypeIds.HWar);
|
||||
if (auth.Has(Claims.Job.Types.ShowSApp))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SApp);
|
||||
if (auth.Has(Claims.Job.Types.ShowSImg))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SImg);
|
||||
if (auth.Has(Claims.Job.Types.ShowSOS))
|
||||
allowedTypes.Add(JobType.JobTypeIds.SOS);
|
||||
if (auth.Has(Claims.Job.Types.ShowUMgmt))
|
||||
allowedTypes.Add(JobType.JobTypeIds.UMgmt);
|
||||
|
||||
Jobs = Jobs.Where(j => allowedTypes.Contains(j.JobTypeId));
|
||||
}
|
||||
|
||||
if (model.ShowStatus)
|
||||
{
|
||||
|
||||
var jobItems = Jobs.Select(j => new JobTableModel.JobTableItemModelIncludeStatus()
|
||||
{
|
||||
Id = j.Id,
|
||||
OpenedDate = j.OpenedDate,
|
||||
ClosedDate = j.ClosedDate,
|
||||
TypeId = j.JobTypeId,
|
||||
TypeDescription = j.JobType.Description,
|
||||
DeviceSerialNumber = j.Device.SerialNumber,
|
||||
DeviceProfileId = j.Device.DeviceProfileId,
|
||||
DeviceModelId = j.Device.DeviceModelId,
|
||||
DeviceModelDescription = j.Device.DeviceModel.Description,
|
||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
||||
UserId = j.UserId,
|
||||
UserDisplayName = j.User.DisplayName,
|
||||
OpenedTechUserId = j.OpenedTechUserId,
|
||||
OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName,
|
||||
Location = j.DeviceHeldLocation,
|
||||
|
||||
JobMetaWarranty_ExternalReference = j.JobMetaWarranty.ExternalReference,
|
||||
JobMetaWarranty_ExternalCompletedDate = j.JobMetaWarranty.ExternalCompletedDate,
|
||||
JobMetaNonWarranty_RepairerLoggedDate = j.JobMetaNonWarranty.RepairerLoggedDate,
|
||||
JobMetaNonWarranty_RepairerCompletedDate = j.JobMetaNonWarranty.RepairerCompletedDate,
|
||||
JobMetaNonWarranty_AccountingChargeAddedDate = j.JobMetaNonWarranty.AccountingChargeAddedDate,
|
||||
JobMetaNonWarranty_AccountingChargePaidDate = j.JobMetaNonWarranty.AccountingChargePaidDate,
|
||||
JobMetaNonWarranty_AccountingChargeRequiredDate = j.JobMetaNonWarranty.AccountingChargeRequiredDate,
|
||||
JobMetaNonWarranty_IsInsuranceClaim = j.JobMetaNonWarranty.IsInsuranceClaim,
|
||||
JobMetaInsurance_ClaimFormSentDate = j.JobMetaInsurance.ClaimFormSentDate,
|
||||
|
||||
WaitingForUserAction = j.WaitingForUserAction,
|
||||
DeviceReadyForReturn = j.DeviceReadyForReturn,
|
||||
DeviceHeld = j.DeviceHeld,
|
||||
DeviceReturnedDate = j.DeviceReturnedDate,
|
||||
JobMetaWarranty_ExternalName = j.JobMetaWarranty.ExternalName,
|
||||
JobMetaNonWarranty_RepairerName = j.JobMetaNonWarranty.RepairerName
|
||||
});
|
||||
|
||||
items = new List<JobTableModel.JobTableItemModel>();
|
||||
foreach (var j in jobItems)
|
||||
{
|
||||
j.StatusId = j.CalculateStatusId();
|
||||
j.StatusDescription = JobBI.Utilities.JobStatusDescription(j.StatusId, j);
|
||||
|
||||
items.Add(j);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
items = Jobs.Select(j => new JobTableModel.JobTableItemModel()
|
||||
{
|
||||
Id = j.Id,
|
||||
OpenedDate = j.OpenedDate,
|
||||
ClosedDate = j.ClosedDate,
|
||||
TypeId = j.JobTypeId,
|
||||
TypeDescription = j.JobType.Description,
|
||||
DeviceSerialNumber = j.Device.SerialNumber,
|
||||
DeviceProfileId = j.Device.DeviceProfileId,
|
||||
DeviceModelId = j.Device.DeviceModelId,
|
||||
DeviceModelDescription = j.Device.DeviceModel.Description,
|
||||
DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress,
|
||||
UserId = j.UserId,
|
||||
UserDisplayName = j.User.DisplayName,
|
||||
OpenedTechUserId = j.OpenedTechUserId,
|
||||
OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName,
|
||||
Location = j.DeviceHeldLocation
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
if (!model.ShowDeviceAddress.HasValue)
|
||||
model.ShowDeviceAddress = Database.DiscoConfiguration.MultiSiteMode;
|
||||
|
||||
foreach (var j in items)
|
||||
if (j.DeviceAddressId.HasValue)
|
||||
j.DeviceAddress = Database.DiscoConfiguration.OrganisationAddresses.GetAddress(j.DeviceAddressId.Value).Name;
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
public static void Fill(this JobTableModel model, DiscoDataContext Database, IQueryable<Job> Jobs)
|
||||
{
|
||||
model.Items = model.DetermineItems(Database, Jobs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using System.IO;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
@@ -14,13 +14,13 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
public static UserAttachment CreateAttachment(this User User, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (string.IsNullOrEmpty(MimeType) || MimeType.Equals("unknown/unknown", StringComparison.OrdinalIgnoreCase))
|
||||
MimeType = Interop.MimeTypes.ResolveMimeType(Filename);
|
||||
|
||||
UserAttachment ua = new UserAttachment()
|
||||
{
|
||||
UserId = User.Id,
|
||||
TechUserId = CreatorUser.Id,
|
||||
UserId = User.UserId,
|
||||
TechUserId = CreatorUser.UserId,
|
||||
Filename = Filename,
|
||||
MimeType = MimeType,
|
||||
Timestamp = DateTime.Now,
|
||||
@@ -57,9 +57,17 @@ namespace Disco.BI.Extensions
|
||||
{
|
||||
return u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).ToList();
|
||||
}
|
||||
public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
||||
public static ADUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties)
|
||||
{
|
||||
return Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(User.Id, AdditionalProperties);
|
||||
return ActiveDirectory.RetrieveADUserAccount(User.UserId, AdditionalProperties);
|
||||
}
|
||||
|
||||
public static bool CanCreateJob(this User u)
|
||||
{
|
||||
if (!JobActionExtensions.CanCreate())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Extensions
|
||||
{
|
||||
public static class UserFlagActionExtensions
|
||||
{
|
||||
|
||||
#region Edit Comments
|
||||
public static bool CanEditComments(this UserFlagAssignment fa)
|
||||
{
|
||||
return UserService.CurrentAuthorization.Has(Claims.User.Actions.EditFlags);
|
||||
}
|
||||
public static void OnEditComments(this UserFlagAssignment fa, string Comments)
|
||||
{
|
||||
if (!fa.CanEditComments())
|
||||
throw new InvalidOperationException("Editing comments for user flags is denied");
|
||||
|
||||
fa.Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
public static bool CanRemove(this UserFlagAssignment fa)
|
||||
{
|
||||
if (fa.RemovedDate.HasValue)
|
||||
return false;
|
||||
|
||||
return UserService.CurrentAuthorization.Has(Claims.User.Actions.RemoveFlags);
|
||||
}
|
||||
public static void OnRemove(this UserFlagAssignment fa, User Technician)
|
||||
{
|
||||
if (!fa.CanRemove())
|
||||
throw new InvalidOperationException("Removing user flags is denied");
|
||||
|
||||
fa.RemovedDate = DateTime.Now;
|
||||
fa.RemovedUserId = Technician.UserId;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
public static bool CanAddUserFlags(this User u)
|
||||
{
|
||||
return UserService.CurrentAuthorization.Has(Claims.User.Actions.AddFlags);
|
||||
}
|
||||
public static bool CanAddUserFlag(this User u, UserFlag flag)
|
||||
{
|
||||
// Shortcut
|
||||
if (!u.CanAddUserFlags())
|
||||
return false;
|
||||
|
||||
// Already has User Flag?
|
||||
if (u.UserFlagAssignments.Any(fa => !fa.RemovedDate.HasValue && fa.UserFlagId == flag.Id))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
public static UserFlagAssignment OnAddUserFlag(this User u, DiscoDataContext Database, UserFlag flag, User Technician, string Comments)
|
||||
{
|
||||
if (!u.CanAddUserFlag(flag))
|
||||
throw new InvalidOperationException("Adding user flag is denied");
|
||||
|
||||
var fa = new UserFlagAssignment()
|
||||
{
|
||||
UserFlagId = flag.Id,
|
||||
UserId = u.UserId,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim()
|
||||
};
|
||||
|
||||
Database.UserFlagAssignments.Add(fa);
|
||||
return fa;
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -23,117 +23,6 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
}
|
||||
|
||||
#region Date/Time Extensions
|
||||
public static string ToFuzzy(this DateTime d)
|
||||
{
|
||||
var n = DateTime.Now;
|
||||
|
||||
// Today
|
||||
if (d.Date == n.Date)
|
||||
{
|
||||
if (d < n)
|
||||
{
|
||||
// Earlier
|
||||
if (d > n.AddMinutes(-1))
|
||||
return "A moment ago";
|
||||
|
||||
if (d > n.AddMinutes(-10))
|
||||
return "A few minutes ago";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Later
|
||||
if (d < n.AddMinutes(1))
|
||||
return "In a moment";
|
||||
|
||||
if (d < n.AddMinutes(10))
|
||||
return "In a few minutes";
|
||||
}
|
||||
|
||||
return string.Format("Today at {0:h:mm tt}", d);
|
||||
}
|
||||
|
||||
if (d.Date < n.Date)
|
||||
{
|
||||
// PAST
|
||||
var dif = n.Subtract(d);
|
||||
|
||||
// Yesterday
|
||||
if (d.Date == n.Date.AddDays(-1))
|
||||
return string.Format("Yesterday at {0:h:mm tt}", d);
|
||||
// Last Week
|
||||
if (dif.TotalDays <= 7)
|
||||
return string.Format("Last {0:dddd} at {0:h:mm tt}", d);
|
||||
// Within 8 Weeks
|
||||
if (d > n.Date.AddMonths(-2))
|
||||
return string.Format("{0} Weeks ago, {1:ddd, d MMM}", (int)(dif.TotalDays / 7), d);
|
||||
// Same Year
|
||||
if (d.Year == n.Year)
|
||||
return string.Format("{0} Months ago, {1:ddd, d MMM}", (int)(dif.TotalDays / 30), d);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Future
|
||||
var dif = d.Subtract(n);
|
||||
|
||||
// Tomorrow
|
||||
if (d.Date == n.Date.AddDays(1))
|
||||
return string.Format("Tomorrow at {0:h:mm tt}", d);
|
||||
// Next Week
|
||||
if (dif.TotalDays <= 7)
|
||||
return string.Format("Next {0:dddd} at {0:h:mm tt}", d);
|
||||
// < 2 Month
|
||||
if (d < n.Date.AddMonths(2))
|
||||
return string.Format("In {0} Weeks, {1:ddd, d MMM}", (int)(dif.TotalDays / 7), d);
|
||||
// Same Year
|
||||
if (d.Year == n.Year)
|
||||
return string.Format("In {0} Months, {1:ddd, d MMM}", (int)(dif.TotalDays / 30), d);
|
||||
}
|
||||
|
||||
return d.ToString("ddd, d MMM yyyy");
|
||||
}
|
||||
public static string ToFuzzy(this DateTime? d, string NullValue = "N/A")
|
||||
{
|
||||
if (d.HasValue)
|
||||
return ToFuzzy(d.Value);
|
||||
else
|
||||
return NullValue;
|
||||
}
|
||||
public static string ToFullDateTime(this DateTime d)
|
||||
{
|
||||
return d.ToString("ddd, d MMM yyyy @ h:mm:sstt");
|
||||
}
|
||||
public static string ToFullDateTime(this DateTime? d, string NullValue = "N/A")
|
||||
{
|
||||
if (d.HasValue)
|
||||
return ToFullDateTime(d.Value);
|
||||
else
|
||||
return NullValue;
|
||||
}
|
||||
public static long ToSortableDateTime(this DateTime? d)
|
||||
{
|
||||
if (d.HasValue)
|
||||
return d.Value.ToBinary();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
public static long ToSortableDateTime(this DateTime d)
|
||||
{
|
||||
return d.ToBinary();
|
||||
}
|
||||
public static string ToJavascriptDateTime(this DateTime d)
|
||||
{
|
||||
return d.ToString("yyyy/MM/dd hh:mm tt");
|
||||
}
|
||||
public static string ToJavascriptDateTime(this DateTime? d)
|
||||
{
|
||||
if (d.HasValue)
|
||||
return d.Value.ToString("yyyy/MM/dd hh:mm tt");
|
||||
else
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Image Extensions
|
||||
|
||||
public static Bitmap RotateImage(this Image Source, float Angle, Brush BackgroundColor = null, bool ResizeIfOver45Deg = true)
|
||||
@@ -277,7 +166,7 @@ namespace Disco.BI.Extensions
|
||||
}
|
||||
public static void SaveJpg(this Image Source, int Quality, Stream OutStream)
|
||||
{
|
||||
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault();
|
||||
ImageCodecInfo jpgCodec = ImageCodecInfo.GetImageEncoders().Where(c => c.MimeType.Equals("image/jpeg", StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
|
||||
if (jpgCodec != null)
|
||||
{
|
||||
if (Quality < 0 || Quality > 100)
|
||||
|
||||
@@ -1,562 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.BI.DeviceBI;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectory
|
||||
{
|
||||
#region Machine Accounts
|
||||
|
||||
private static readonly string[] MachineLoadProperties = {
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"dNSHostName",
|
||||
"netbootGUID",
|
||||
"isCriticalSystemObject"
|
||||
};
|
||||
public static ActiveDirectoryMachineAccount GetMachineAccount(string ComputerName, System.Guid? UUIDNetbootGUID = null, System.Guid? MacAddressNetbootGUID = null, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ComputerName))
|
||||
throw new System.ArgumentException("Invalid Computer Name - Empty", "ComputerName");
|
||||
if (ComputerName.Contains("\\"))
|
||||
ComputerName = ComputerName.Substring(checked(ComputerName.IndexOf("\\") + 1));
|
||||
if (ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name - Length > 24", "ComputerName");
|
||||
string sAMAccountName = ComputerName;
|
||||
if (!sAMAccountName.EndsWith("$"))
|
||||
sAMAccountName = string.Format("{0}$", sAMAccountName);
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = AdditionalProperties == null ? MachineLoadProperties : MachineLoadProperties.Concat(AdditionalProperties).ToArray();
|
||||
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=computer)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.ActiveDirectoryMachineAccountFromSearchResult(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
|
||||
if (UUIDNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)), loadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.ActiveDirectoryMachineAccountFromSearchResult(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MacAddressNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)), loadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.ActiveDirectoryMachineAccountFromSearchResult(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static ActiveDirectoryMachineAccount ActiveDirectoryMachineAccountFromSearchResult(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string sAMAccountName = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSDDLString((byte[])result.Properties["objectSid"][0]);
|
||||
|
||||
var dNSNameProperty = result.Properties["dNSHostName"];
|
||||
string dNSName = null;
|
||||
if (dNSNameProperty.Count > 0)
|
||||
dNSName = dNSNameProperty[0].ToString();
|
||||
else
|
||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
bool isCriticalSystemObject = (bool)result.Properties["isCriticalSystemObject"][0];
|
||||
|
||||
System.Guid netbootGUIDResult = default(System.Guid);
|
||||
ResultPropertyValueCollection netbootGUIDProp = result.Properties["netbootGUID"];
|
||||
if (netbootGUIDProp.Count > 0)
|
||||
{
|
||||
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
if (AdditionalProperties != null)
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryMachineAccount
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
NetbootGUID = netbootGUIDResult,
|
||||
Path = result.Path,
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
DnsName = dNSName,
|
||||
IsCriticalSystemObject = isCriticalSystemObject,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public static string OfflineDomainJoinProvision(ref ActiveDirectoryMachineAccount ExistingAccount, string ComputerName, string OrganisationalUnit = null, string EnrolSessionId = null)
|
||||
{
|
||||
if (ExistingAccount != null && ExistingAccount.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", ExistingAccount.DistinguishedName));
|
||||
|
||||
string DJoinResult = null;
|
||||
if (string.IsNullOrWhiteSpace(ComputerName) || ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
||||
|
||||
// Added 2012-10-25 G#
|
||||
// Ensure Specified OU Exists
|
||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
||||
{
|
||||
var ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
try
|
||||
{
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
if (ou == null)
|
||||
{
|
||||
throw new Exception("OU's Directory Entry couldn't be found");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", ouPath), "OrganisationalUnit", ex);
|
||||
}
|
||||
}
|
||||
// End Added 2012-10-25 G#
|
||||
|
||||
// Delete Existing
|
||||
if (ExistingAccount != null)
|
||||
ExistingAccount.DeleteAccount();
|
||||
|
||||
string tempFileName = System.IO.Path.GetTempFileName();
|
||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0},{1}\"", OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName) : string.Empty;
|
||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
||||
ActiveDirectoryHelpers.DefaultDomainName,
|
||||
ActiveDirectoryHelpers.DefaultDomainPDCName,
|
||||
ComputerName,
|
||||
argumentOU,
|
||||
tempFileName
|
||||
);
|
||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
LoadUserProfile = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, string.Format("{0} {1}{2}", "DJOIN.EXE", arguments, System.Environment.NewLine));
|
||||
}
|
||||
|
||||
string stdOutput;
|
||||
string stdError;
|
||||
using (Process commandProc = Process.Start(commandStarter))
|
||||
{
|
||||
commandProc.WaitForExit(20000);
|
||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
||||
stdError = commandProc.StandardError.ReadToEnd();
|
||||
}
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdOutput + System.Environment.NewLine);
|
||||
if (!string.IsNullOrWhiteSpace(stdError))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdError + System.Environment.NewLine);
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(tempFileName))
|
||||
{
|
||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
||||
System.IO.File.Delete(tempFileName);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
||||
ExistingAccount = ActiveDirectory.GetMachineAccount(ComputerName);
|
||||
return DJoinResult;
|
||||
}
|
||||
|
||||
#region Users
|
||||
|
||||
private static readonly string[] UserLoadProperties = {
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"displayName",
|
||||
"sn",
|
||||
"givenName",
|
||||
"memberOf",
|
||||
"primaryGroupID",
|
||||
"mail",
|
||||
"telephoneNumber"
|
||||
};
|
||||
public static List<ActiveDirectoryUserAccount> SearchUsers(string term)
|
||||
{
|
||||
List<ActiveDirectoryUserAccount> users = new List<ActiveDirectoryUserAccount>();
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
||||
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectCategory=Person)(objectCategory=Person)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", term), UserLoadProperties, SearchScope.Subtree))
|
||||
{
|
||||
searcher.SizeLimit = 30;
|
||||
SearchResultCollection results = searcher.FindAll();
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
users.Add(ActiveDirectory.ActiveDirectoryUserAccountFromSearchResult(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
private static ActiveDirectoryUserAccount ActiveDirectoryUserAccountFromSearchResult(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string username = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
byte[] objectSid = (byte[])result.Properties["objectSid"][0];
|
||||
string objectSidSDDL = ActiveDirectoryHelpers.ConvertBytesToSDDLString(objectSid);
|
||||
|
||||
ResultPropertyValueCollection displayNameProp = result.Properties["displayName"];
|
||||
string displayName = username;
|
||||
if (displayNameProp.Count > 0)
|
||||
displayName = displayNameProp[0].ToString();
|
||||
string surname = null;
|
||||
ResultPropertyValueCollection surnameProp = result.Properties["sn"];
|
||||
if (surnameProp.Count > 0)
|
||||
surname = surnameProp[0].ToString();
|
||||
string givenName = null;
|
||||
ResultPropertyValueCollection givenNameProp = result.Properties["givenName"];
|
||||
if (givenNameProp.Count > 0)
|
||||
givenName = givenNameProp[0].ToString();
|
||||
string email = null;
|
||||
ResultPropertyValueCollection emailProp = result.Properties["mail"];
|
||||
if (emailProp.Count > 0)
|
||||
email = emailProp[0].ToString();
|
||||
string phone = null;
|
||||
ResultPropertyValueCollection phoneProp = result.Properties["telephoneNumber"];
|
||||
if (phoneProp.Count > 0)
|
||||
phone = phoneProp[0].ToString();
|
||||
|
||||
int primaryGroupID = (int)result.Properties["primaryGroupID"][0];
|
||||
string primaryGroupSid = ActiveDirectoryHelpers.ConvertBytesToSDDLString(ActiveDirectoryHelpers.BuildPrimaryGroupSid(objectSid, primaryGroupID));
|
||||
var groupDistinguishedNames = result.Properties["memberOf"].Cast<string>().ToList();
|
||||
groupDistinguishedNames.Add(ActiveDirectoryCachedGroups.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid));
|
||||
List<string> groups = ActiveDirectoryCachedGroups.GetGroups(groupDistinguishedNames).ToList();
|
||||
|
||||
//foreach (string groupCN in result.Properties["memberOf"])
|
||||
//{
|
||||
// Removed 2012-11-30 G# - Moved to Recursive Cache
|
||||
//var groupCNlower = groupCN.ToLower();
|
||||
//if (groupCNlower.StartsWith("cn="))
|
||||
// groups.Add(groupCNlower.Substring(3, groupCNlower.IndexOf(",") - 3));
|
||||
// End Removed 2012-11-30 G#
|
||||
//}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
if (AdditionalProperties != null)
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryUserAccount
|
||||
{
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
Name = name,
|
||||
Surname = surname,
|
||||
GivenName = givenName,
|
||||
Email = email,
|
||||
Phone = phone,
|
||||
DistinguishedName = distinguishedName,
|
||||
SamAccountName = username,
|
||||
DisplayName = displayName,
|
||||
SecurityIdentifier = objectSidSDDL,
|
||||
Groups = groups,
|
||||
Path = result.Path,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
public static ActiveDirectoryUserAccount GetUserAccount(string Username, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Username))
|
||||
throw new System.ArgumentException("Invalid User Account", "Username");
|
||||
string sAMAccountName = Username;
|
||||
if (sAMAccountName.Contains("\\"))
|
||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = AdditionalProperties == null ? UserLoadProperties : UserLoadProperties.Concat(AdditionalProperties).ToArray();
|
||||
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Person)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
return ActiveDirectory.ActiveDirectoryUserAccountFromSearchResult(dResult, AdditionalProperties);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Organisation Units
|
||||
|
||||
public static List<ActiveDirectoryOrganisationalUnit> GetOrganisationalUnitStructure()
|
||||
{
|
||||
ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Children = new System.Collections.Generic.List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref DomainOUs, entry);
|
||||
}
|
||||
return DomainOUs.Children;
|
||||
}
|
||||
private static void GetOrganisationalUnitStructure_Recursive(ref ActiveDirectoryOrganisationalUnit ParentOU, DirectoryEntry Container)
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName"
|
||||
}, SearchScope.OneLevel))
|
||||
{
|
||||
using (SearchResultCollection results = searcher.FindAll())
|
||||
{
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
string i = result.Properties["name"][0].ToString();
|
||||
string dn = result.Properties["distinguishedName"][0].ToString();
|
||||
ActiveDirectoryOrganisationalUnit ChildOU = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Name = i,
|
||||
Path = dn.Substring(0, dn.IndexOf(",DC=")),
|
||||
Children = new List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry());
|
||||
if (ChildOU.Children.Count == 0)
|
||||
ChildOU.Children = null;
|
||||
ParentOU.Children.Add(ChildOU);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Groups
|
||||
|
||||
private static readonly string[] GroupLoadProperties = {
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"cn",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"memberOf"
|
||||
};
|
||||
public static ActiveDirectoryGroup GetGroup(string SamAccountName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SamAccountName))
|
||||
throw new System.ArgumentException("Invalid Group Account", "SamAccountName");
|
||||
string sAMAccountName = SamAccountName;
|
||||
if (sAMAccountName.Contains("\\"))
|
||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Group)(objectSid={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), GroupLoadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectoryGroupFromSearchResult(dResult);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static ActiveDirectoryGroup GetGroupFromDistinguishedName(string DistinguishedName)
|
||||
{
|
||||
ActiveDirectoryGroup group = null;
|
||||
|
||||
using (DirectoryEntry groupDE = new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, DistinguishedName)))
|
||||
{
|
||||
if (groupDE != null)
|
||||
{
|
||||
return ActiveDirectoryGroupFromDirectoryEntry(groupDE);
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
public static ActiveDirectoryGroup GetGroupFromSecurityIdentifier(string SecurityIdentifier)
|
||||
{
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var sidBytes = ActiveDirectoryHelpers.ConvertSDDLStringToBytes(SecurityIdentifier);
|
||||
var sidBinaryString = ActiveDirectoryHelpers.ConvertBytesToBinarySidString(sidBytes);
|
||||
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Group)(objectSid={0}))", sidBinaryString), GroupLoadProperties, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectoryGroupFromSearchResult(dResult);
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<ActiveDirectoryGroup> SearchGroups(string term)
|
||||
{
|
||||
List<ActiveDirectoryGroup> results = new List<ActiveDirectoryGroup>();
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
||||
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))", term), GroupLoadProperties, SearchScope.Subtree))
|
||||
{
|
||||
searcher.SizeLimit = 30;
|
||||
SearchResultCollection searchResults = searcher.FindAll();
|
||||
foreach (SearchResult result in searchResults)
|
||||
{
|
||||
results.Add(ActiveDirectory.ActiveDirectoryGroupFromSearchResult(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ActiveDirectoryGroup ActiveDirectoryGroupFromDirectoryEntry(DirectoryEntry entry)
|
||||
{
|
||||
var name = (string)entry.Properties["name"].Value;
|
||||
var distinguishedName = (string)entry.Properties["distinguishedName"].Value;
|
||||
var cn = (string)entry.Properties["cn"].Value;
|
||||
var sAMAccountName = (string)entry.Properties["sAMAccountName"].Value;
|
||||
var objectSid = ActiveDirectoryHelpers.ConvertBytesToSDDLString((byte[])entry.Properties["objectSid"].Value);
|
||||
var memberOf = entry.Properties["memberOf"].Cast<string>().ToList();
|
||||
|
||||
return new ActiveDirectoryGroup()
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
CommonName = cn,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
MemberOf = memberOf
|
||||
};
|
||||
}
|
||||
private static ActiveDirectoryGroup ActiveDirectoryGroupFromSearchResult(SearchResult result)
|
||||
{
|
||||
var name = (string)result.Properties["name"][0];
|
||||
var distinguishedName = (string)result.Properties["distinguishedName"][0];
|
||||
var cn = (string)result.Properties["cn"][0];
|
||||
var sAMAccountName = (string)result.Properties["sAMAccountName"][0];
|
||||
var objectSid = ActiveDirectoryHelpers.ConvertBytesToSDDLString((byte[])result.Properties["objectSid"][0]);
|
||||
var memberOf = result.Properties["memberOf"].Cast<string>().ToList();
|
||||
|
||||
return new ActiveDirectoryGroup()
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
CommonName = cn,
|
||||
SamAccountName = sAMAccountName,
|
||||
SecurityIdentifier = objectSid,
|
||||
MemberOf = memberOf
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
||||
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray();
|
||||
|
||||
public static IActiveDirectoryObject GetObject(string SamAccountName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(SamAccountName))
|
||||
throw new System.ArgumentException("Invalid Object Account Name", "SamAccountName");
|
||||
string sAMAccountName = SamAccountName;
|
||||
if (sAMAccountName.Contains("\\"))
|
||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), ObjectLoadPropertiesAll, SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
var objectCategory = (string)dResult.Properties["objectCategory"][0];
|
||||
objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower();
|
||||
switch (objectCategory)
|
||||
{
|
||||
case "cn=person":
|
||||
return ActiveDirectoryUserAccountFromSearchResult(dResult);
|
||||
case "cn=computer":
|
||||
return ActiveDirectoryMachineAccountFromSearchResult(dResult);
|
||||
case "cn=group":
|
||||
return ActiveDirectoryGroupFromSearchResult(dResult);
|
||||
default:
|
||||
throw new InvalidOperationException("Unexpected objectCategory");
|
||||
}
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryCachedGroups : ScheduledTask
|
||||
{
|
||||
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _SecurityIdentifierCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
|
||||
private static ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>> _DistinguishedNameCache = new ConcurrentDictionary<string, Tuple<ActiveDirectoryGroup, DateTime>>();
|
||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
||||
|
||||
public static IEnumerable<string> GetGroups(IEnumerable<string> DistinguishedNames)
|
||||
{
|
||||
List<ActiveDirectoryGroup> groups = new List<ActiveDirectoryGroup>();
|
||||
|
||||
foreach (var distinguishedName in DistinguishedNames)
|
||||
foreach (var group in GetGroupsRecursive(distinguishedName, new Stack<ActiveDirectoryGroup>()))
|
||||
if (!groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
yield return group.SamAccountName;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> GetGroups(string DistinguishedName)
|
||||
{
|
||||
foreach (var group in GetGroupsRecursive(DistinguishedName, new Stack<ActiveDirectoryGroup>()))
|
||||
yield return group.SamAccountName;
|
||||
}
|
||||
public static string GetGroupsDistinguishedNameForSecurityIdentifier(string SecurityIdentifier)
|
||||
{
|
||||
var group = GetGroupBySecurityIdentifier(SecurityIdentifier);
|
||||
if (group == null)
|
||||
return null;
|
||||
else
|
||||
return group.DistinguishedName;
|
||||
}
|
||||
private static IEnumerable<ActiveDirectoryGroup> GetGroupsRecursive(string DistinguishedName, Stack<ActiveDirectoryGroup> RecursiveTree)
|
||||
{
|
||||
var group = GetGroup(DistinguishedName);
|
||||
|
||||
if (group != null && !RecursiveTree.Contains(group))
|
||||
{
|
||||
yield return group;
|
||||
|
||||
if (group.MemberOf != null)
|
||||
{
|
||||
RecursiveTree.Push(group);
|
||||
|
||||
foreach (var parentDistinguishedName in group.MemberOf)
|
||||
foreach (var parentGroup in GetGroupsRecursive(parentDistinguishedName, RecursiveTree))
|
||||
yield return parentGroup;
|
||||
|
||||
RecursiveTree.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ActiveDirectoryGroup GetGroup(string DistinguishedName)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TryCache(DistinguishedName);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.GetGroupFromDistinguishedName(DistinguishedName);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
private static ActiveDirectoryGroup GetGroupBySecurityIdentifier(string SecurityIdentifier)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = TrySecurityIdentifierCache(SecurityIdentifier);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ActiveDirectory.GetGroupFromSecurityIdentifier(SecurityIdentifier);
|
||||
SetValue(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<ActiveDirectoryGroup, DateTime> TryCache(string DistinguishedName)
|
||||
{
|
||||
string distinguishedName = DistinguishedName.ToLower();
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_DistinguishedNameCache.TryGetValue(distinguishedName, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (_DistinguishedNameCache.TryRemove(distinguishedName, out groupRecord))
|
||||
_SecurityIdentifierCache.TryRemove(groupRecord.Item1.SecurityIdentifier, out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static Tuple<ActiveDirectoryGroup, DateTime> TrySecurityIdentifierCache(string SecurityIdentifier)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_SecurityIdentifierCache.TryGetValue(SecurityIdentifier, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
{
|
||||
if (_SecurityIdentifierCache.TryRemove(SecurityIdentifier, out groupRecord))
|
||||
_DistinguishedNameCache.TryRemove(groupRecord.Item1.DistinguishedName.ToLower(), out groupRecord);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static bool SetValue(ActiveDirectoryGroup Group)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord = new Tuple<ActiveDirectoryGroup, DateTime>(Group, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
||||
Tuple<ActiveDirectoryGroup, DateTime> oldGroupRecord;
|
||||
|
||||
string key = Group.DistinguishedName.ToLower();
|
||||
if (_DistinguishedNameCache.ContainsKey(key))
|
||||
{
|
||||
if (_DistinguishedNameCache.TryGetValue(key, out oldGroupRecord))
|
||||
{
|
||||
_DistinguishedNameCache.TryUpdate(key, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_DistinguishedNameCache.TryAdd(key, groupRecord);
|
||||
}
|
||||
|
||||
string securityIdentifier = Group.SecurityIdentifier;
|
||||
if (_SecurityIdentifierCache.ContainsKey(securityIdentifier))
|
||||
{
|
||||
if (_SecurityIdentifierCache.TryGetValue(securityIdentifier, out oldGroupRecord))
|
||||
{
|
||||
_SecurityIdentifierCache.TryUpdate(securityIdentifier, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_SecurityIdentifierCache.TryAdd(securityIdentifier, groupRecord);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CleanStaleCache()
|
||||
{
|
||||
// Clean Cache
|
||||
var groupKeys = _DistinguishedNameCache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_DistinguishedNameCache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
{
|
||||
_DistinguishedNameCache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean SID Cache
|
||||
groupKeys = _SecurityIdentifierCache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ActiveDirectoryGroup, DateTime> groupRecord;
|
||||
if (_SecurityIdentifierCache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
{
|
||||
_SecurityIdentifierCache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Run @ every 15mins
|
||||
|
||||
// Next 15min interval
|
||||
DateTime now = DateTime.Now;
|
||||
int mins = (15 - (now.Minute % 15));
|
||||
if (mins < 10)
|
||||
mins += 15;
|
||||
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
|
||||
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
CleanStaleCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectoryGroupExtensions
|
||||
{
|
||||
|
||||
public static IEnumerable<Tuple<string, string>> GetMembers(ActiveDirectoryGroup group)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryHelpers
|
||||
{
|
||||
#region Static Cached Properties
|
||||
private static string _DefaultDomainName;
|
||||
private static string _DefaultDomainPDCName;
|
||||
private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
|
||||
private static string _DefaultDomainNetBiosName;
|
||||
private static string _DefaultDomainQualifiedName;
|
||||
private static string _DefaultLdapPath;
|
||||
private static bool _DetermineDomainProperties_Loaded = false;
|
||||
private static object _DetermineDomainProperties_Lock = new object();
|
||||
internal static string DefaultDomainName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainPDCName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainPDCName;
|
||||
}
|
||||
}
|
||||
internal static System.Collections.Generic.List<string> DefaultDomainDCNames
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainDCNames;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainNetBiosName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainQualifiedName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultLdapPath
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultLdapPath;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDCLdapPath(string DC)
|
||||
{
|
||||
return string.Format("LDAP://{0}/", DC);
|
||||
}
|
||||
internal static DirectoryEntry DefaultLdapRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
}
|
||||
internal static DirectoryEntry DefaultDCLdapRoot(string DC)
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
|
||||
private static void DetermineDomainProperties()
|
||||
{
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
|
||||
{
|
||||
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
|
||||
foreach (DomainController dc in domain.DomainControllers)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
|
||||
ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
|
||||
{
|
||||
SearchResult result = searcher.FindOne();
|
||||
if (result != null)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static string ConvertBytesToSDDLString(byte[] SID)
|
||||
{
|
||||
SecurityIdentifier sID = new SecurityIdentifier(SID, 0);
|
||||
|
||||
return sID.ToString();
|
||||
}
|
||||
|
||||
internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString)
|
||||
{
|
||||
SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString);
|
||||
|
||||
var sidBytes = new byte[sID.BinaryLength];
|
||||
|
||||
sID.GetBinaryForm(sidBytes, 0);
|
||||
|
||||
return sidBytes;
|
||||
}
|
||||
|
||||
internal static byte[] BuildPrimaryGroupSid(byte[] UserSID, int PrimaryGroupId)
|
||||
{
|
||||
var groupSid = (byte[])UserSID.Clone();
|
||||
|
||||
int ridOffset = groupSid.Length - 4;
|
||||
int groupId = PrimaryGroupId;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
groupSid[ridOffset + i] = (byte)(groupId & 0xFF);
|
||||
groupId >>= 8;
|
||||
}
|
||||
|
||||
return groupSid;
|
||||
}
|
||||
|
||||
internal static string ConvertBytesToBinarySidString(byte[] SID)
|
||||
{
|
||||
StringBuilder escapedSid = new StringBuilder();
|
||||
|
||||
foreach (var sidByte in SID)
|
||||
{
|
||||
escapedSid.Append('\\');
|
||||
escapedSid.Append(sidByte.ToString("x2"));
|
||||
}
|
||||
|
||||
return escapedSid.ToString();
|
||||
}
|
||||
|
||||
internal static string EscapeLdapQuery(string query)
|
||||
{
|
||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
||||
}
|
||||
internal static string FormatGuidForLdapQuery(System.Guid g)
|
||||
{
|
||||
checked
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
byte[] array = g.ToByteArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte b = array[i];
|
||||
sb.Append("\\");
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,301 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Text;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Management;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectoryMachineAccountExtensions
|
||||
{
|
||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
DeleteAccountRecursive(machineDE);
|
||||
|
||||
using (var machineDEParent = machineDE.Parent)
|
||||
{
|
||||
machineDEParent.Children.Remove(machineDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void DeleteAccountRecursive(DirectoryEntry parent)
|
||||
{
|
||||
List<DirectoryEntry> children = new List<DirectoryEntry>();
|
||||
foreach (DirectoryEntry child in parent.Children)
|
||||
children.Add(child);
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
DeleteAccountRecursive(child);
|
||||
parent.Children.Remove(child);
|
||||
child.Dispose();
|
||||
}
|
||||
}
|
||||
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, System.Guid updatedNetbootGUID)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection netbootGUIDProp = machineDE.Properties["netbootGUID"];
|
||||
bool flag = netbootGUIDProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
netbootGUIDProp.Clear();
|
||||
}
|
||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
|
||||
{
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection descriptionProp = machineDE.Properties["description"];
|
||||
if (descriptionProp.Count > 0)
|
||||
{
|
||||
descriptionProp.Clear();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(Description))
|
||||
{
|
||||
descriptionProp.Add(Description);
|
||||
}
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
|
||||
{
|
||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
||||
|
||||
if (Device.AssignedUserId != null)
|
||||
{
|
||||
descriptionBuilder.Append(Device.AssignedUser.Id).Append(" (").Append(Device.AssignedUser.DisplayName).Append("); ");
|
||||
}
|
||||
|
||||
if (Device.DeviceModelId.HasValue)
|
||||
{
|
||||
descriptionBuilder.Append(Device.DeviceModel.Description).Append("; ");
|
||||
}
|
||||
|
||||
descriptionBuilder.Append(Device.DeviceProfile.Description).Append(";");
|
||||
|
||||
string description = descriptionBuilder.ToString().Trim();
|
||||
if (description.Length > 1024)
|
||||
{
|
||||
description = description.Substring(0, 1024);
|
||||
}
|
||||
account.SetDescription(description);
|
||||
}
|
||||
|
||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
int updatedAccountControl = (accountControl | 2);
|
||||
if (accountControl != updatedAccountControl)
|
||||
{
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
if ((accountControl & 2) == 2)
|
||||
{
|
||||
int updatedAccountControl = (accountControl ^ 2);
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
System.Guid netbootGUID = System.Guid.Empty;
|
||||
bool flag = !string.IsNullOrWhiteSpace(UUID);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(UUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = !string.IsNullOrWhiteSpace(MACAddress);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(MACAddress);
|
||||
}
|
||||
}
|
||||
flag = (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID);
|
||||
bool UpdateNetbootGUID;
|
||||
if (flag)
|
||||
{
|
||||
account.SetNetbootGUID(netbootGUID);
|
||||
UpdateNetbootGUID = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNetbootGUID = false;
|
||||
}
|
||||
return UpdateNetbootGUID;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
||||
{
|
||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
||||
bool flag = strippedMACAddress.Length == 12;
|
||||
System.Guid NetbootGUIDFromMACAddress;
|
||||
if (flag)
|
||||
{
|
||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
||||
NetbootGUIDFromMACAddress = guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
||||
}
|
||||
return NetbootGUIDFromMACAddress;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromUUID(string UUID)
|
||||
{
|
||||
System.Guid result = new System.Guid(UUID);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.SecurityIdentifier;
|
||||
case "netbootguid":
|
||||
return account.NetbootGUID;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
|
||||
{
|
||||
using (var p = new Ping())
|
||||
{
|
||||
PingReply reply = p.Send(account.DnsName, Timeout);
|
||||
return reply.Status;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't Work - WMI Limitation?
|
||||
// G# - 2012-06-18
|
||||
//public static void OnlineRenameComputer(this ActiveDirectoryMachineAccount account, string NewComputerName)
|
||||
//{
|
||||
// if (account.IsCriticalSystemObject)
|
||||
// throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
// try
|
||||
// {
|
||||
// IPStatus pingResult = account.PingComputer();
|
||||
// if (pingResult != IPStatus.Success)
|
||||
// throw new Exception(string.Format("Ping Error Result: {0}", pingResult.ToString()));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw new Exception(string.Format("Error trying to Ping the Device: {0}; {1}", account.DnsName, ex.Message), ex);
|
||||
// }
|
||||
|
||||
// ConnectionOptions wmiConnectionOptions = new ConnectionOptions()
|
||||
// {
|
||||
// Authentication = AuthenticationLevel.PacketPrivacy,
|
||||
// Impersonation = ImpersonationLevel.Impersonate,
|
||||
// EnablePrivileges = true,
|
||||
// Timeout = new TimeSpan(0, 0, 6)
|
||||
// };
|
||||
// ManagementPath wmiPath = new ManagementPath()
|
||||
// {
|
||||
// Server = account.DnsName,
|
||||
// NamespacePath = @"root\cimv2",
|
||||
// ClassName = "Win32_ComputerSystem"
|
||||
// };
|
||||
|
||||
// ManagementScope wmiScope = new ManagementScope(wmiPath, wmiConnectionOptions);
|
||||
|
||||
// ObjectGetOptions wmiGetOptions = new ObjectGetOptions() { Timeout = new TimeSpan(0, 1, 0) };
|
||||
|
||||
// using (ManagementClass wmiClass = new ManagementClass(wmiScope, wmiPath, wmiGetOptions))
|
||||
// {
|
||||
// foreach (ManagementObject wmiWin32ComputerSystem in wmiClass.GetInstances())
|
||||
// {
|
||||
// UInt32 result = (UInt32)wmiWin32ComputerSystem.InvokeMethod("Rename", new object[] { NewComputerName });
|
||||
// if (result != 0)
|
||||
// throw new Exception(string.Format("Error Renaming Computer; WMI Remote Method 'Rename' returned: {0}", result));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
public static void MoveOrganisationUnit(this ActiveDirectoryMachineAccount account, string NewOrganisationUnit)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
var parentDistinguishedName = account.ParentDistinguishedName();
|
||||
|
||||
if (parentDistinguishedName != null && !parentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
string ouPath;
|
||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
||||
ouPath = string.Format("{0}CN=Computers,{1}", ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
else
|
||||
ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, NewOrganisationUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
using (DirectoryEntry i = new DirectoryEntry(account.Path) { UsePropertyCache = false })
|
||||
{
|
||||
i.MoveTo(ou);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ParentDistinguishedName(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
// Determine Parent
|
||||
if (!string.IsNullOrWhiteSpace(account.DistinguishedName))
|
||||
return account.DistinguishedName.Substring(0, account.DistinguishedName.IndexOf(",DC=")).Substring(account.DistinguishedName.IndexOf(",") + 1);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,264 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Models.Repository;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Reflection;
|
||||
using Disco.Services.Tasks;
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryUpdateLastNetworkLogonDateJob : ScheduledTask
|
||||
{
|
||||
|
||||
public override string TaskName { get { return "Active Directory - Update Last Network Logon Dates Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
int changeCount;
|
||||
|
||||
this.Status.UpdateStatus(1, "Starting", "Connecting to the Database and initializing the environment");
|
||||
using (DiscoDataContext database = new DiscoDataContext())
|
||||
{
|
||||
UpdateLastNetworkLogonDates(database, this.Status);
|
||||
this.Status.UpdateStatus(95, "Updating Database", "Writing last network logon dates to the Database");
|
||||
changeCount = database.SaveChanges();
|
||||
this.Status.Finished(string.Format("{0} Device last network logon dates updated", changeCount), "/Config/SystemConfig");
|
||||
}
|
||||
|
||||
SystemLog.LogInformation(new string[]
|
||||
{
|
||||
"Updated LastNetworkLogon Device Property for Device/s",
|
||||
changeCount.ToString()
|
||||
});
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ActiveDirectoryUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new ActiveDirectoryUpdateLastNetworkLogonDateJob();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(Device Device)
|
||||
{
|
||||
System.DateTime? computerLastLogonDate = Device.LastNetworkLogonDate;
|
||||
if (!string.IsNullOrEmpty(Device.ComputerName))
|
||||
{
|
||||
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
Ping p = new Ping();
|
||||
PingReply pr;
|
||||
try
|
||||
{
|
||||
pr = p.Send(dcName, 500);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (p != null)
|
||||
{
|
||||
((System.IDisposable)p).Dispose();
|
||||
}
|
||||
}
|
||||
if (pr.Status == IPStatus.Success)
|
||||
{
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
|
||||
{
|
||||
DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectCategory=Computer)(sAMAccountName={0}$))", ActiveDirectoryHelpers.EscapeLdapQuery(Device.ComputerName)), new string[]
|
||||
{
|
||||
"lastLogon"
|
||||
}, SearchScope.Subtree);
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
ResultPropertyValueCollection dProp = dResult.Properties["lastLogon"];
|
||||
if (dProp != null && dProp.Count > 0)
|
||||
{
|
||||
long lastLogonInt = (long)dProp[0];
|
||||
if (lastLogonInt > 0L)
|
||||
{
|
||||
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
|
||||
if (computerLastLogonDate.HasValue)
|
||||
{
|
||||
if (System.DateTime.Compare(computerLastLogonDate.Value, computerNameDate) < 0)
|
||||
{
|
||||
computerLastLogonDate = computerNameDate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
computerLastLogonDate = computerNameDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemLog.LogError(new string[]
|
||||
{
|
||||
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateDeviceLastNetworkLogonDate)", dcName)
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
SystemLog.LogException("UpdateDeviceLastNetworkLogonDate", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool UpdateLastNetworkLogonDate;
|
||||
if (computerLastLogonDate.HasValue)
|
||||
{
|
||||
if (!Device.LastNetworkLogonDate.HasValue)
|
||||
{
|
||||
Device.LastNetworkLogonDate = computerLastLogonDate;
|
||||
UpdateLastNetworkLogonDate = true;
|
||||
return UpdateLastNetworkLogonDate;
|
||||
}
|
||||
if (System.DateTime.Compare(computerLastLogonDate.Value, Device.LastNetworkLogonDate.Value) > 0)
|
||||
{
|
||||
Device.LastNetworkLogonDate = computerLastLogonDate;
|
||||
UpdateLastNetworkLogonDate = true;
|
||||
return UpdateLastNetworkLogonDate;
|
||||
}
|
||||
}
|
||||
UpdateLastNetworkLogonDate = false;
|
||||
return UpdateLastNetworkLogonDate;
|
||||
}
|
||||
private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status)
|
||||
{
|
||||
System.Collections.Generic.Dictionary<string, System.DateTime> computerLastLogonDates = new System.Collections.Generic.Dictionary<string, System.DateTime>();
|
||||
|
||||
int progressDCCountTotal = ActiveDirectoryHelpers.DefaultDomainDCNames.Count;
|
||||
int progressDCCount = 0;
|
||||
double progressDCProgress = 0;
|
||||
if (progressDCCountTotal > 0)
|
||||
progressDCProgress = 90 / progressDCCountTotal;
|
||||
|
||||
foreach (var dcName in ActiveDirectoryHelpers.DefaultDomainDCNames)
|
||||
{
|
||||
try
|
||||
{
|
||||
PingReply pr;
|
||||
using (Ping p = new Ping())
|
||||
{
|
||||
pr = p.Send(dcName, 2000);
|
||||
}
|
||||
if (pr.Status == IPStatus.Success)
|
||||
{
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultDCLdapRoot(dcName))
|
||||
{
|
||||
double progressDCStart = 5 + (progressDCCount * progressDCProgress);
|
||||
status.UpdateStatus(progressDCStart, string.Format("Querying Domain Controller: {0}", dcName), "Searching...");
|
||||
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, "(objectCategory=Computer)", new string[] { "sAMAccountName", "lastLogon" }, SearchScope.Subtree))
|
||||
{
|
||||
using (SearchResultCollection dResults = dSearcher.FindAll())
|
||||
{
|
||||
|
||||
int progressItemCount = 0;
|
||||
double progressItemProgress = dResults.Count == 0 ? 0 : (progressDCProgress / dResults.Count);
|
||||
|
||||
foreach (SearchResult dResult in dResults)
|
||||
{
|
||||
ResultPropertyValueCollection dProp = dResult.Properties["sAMAccountName"];
|
||||
if (dProp != null && dProp.Count > 0)
|
||||
{
|
||||
string computerName = ((string)dProp[0]).TrimEnd(new char[] { '$' }).ToUpper();
|
||||
|
||||
if (progressItemCount % 150 == 0) // Only Update Status every 150 devices
|
||||
status.UpdateStatus(progressDCStart + (progressItemProgress * progressItemCount), string.Format("Analysing Device: {0}", computerName));
|
||||
|
||||
dProp = dResult.Properties["lastLogon"];
|
||||
if (dProp != null && dProp.Count > 0)
|
||||
{
|
||||
long lastLogonInt = (long)dProp[0];
|
||||
if (lastLogonInt > 0L)
|
||||
{
|
||||
System.DateTime computerNameDate = System.DateTime.FromFileTime(lastLogonInt);
|
||||
System.DateTime existingDate;
|
||||
if (computerLastLogonDates.TryGetValue(computerName, out existingDate))
|
||||
{
|
||||
if (System.DateTime.Compare(existingDate, computerNameDate) < 0)
|
||||
{
|
||||
computerLastLogonDates[computerName] = computerNameDate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
computerLastLogonDates[computerName] = computerNameDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
progressItemCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SystemLog.LogError(new string[]
|
||||
{
|
||||
string.Format("Unable to ping Domain Controller: '{0}' (ref: Disco.BI.Interop.ActiveDirectory.ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDates)", dcName)
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
SystemLog.LogException("UpdateLastNetworkLogonDates", ex);
|
||||
}
|
||||
progressDCCount++;
|
||||
}
|
||||
|
||||
|
||||
foreach (Device d in Database.Devices.Where(device => device.ComputerName != null))
|
||||
{
|
||||
DateTime computerLastLogonDate;
|
||||
if (computerLastLogonDates.TryGetValue(d.ComputerName.ToUpper(), out computerLastLogonDate))
|
||||
{
|
||||
if (d.LastNetworkLogonDate.HasValue)
|
||||
{
|
||||
// Change accuracy to the second
|
||||
computerLastLogonDate = new DateTime((computerLastLogonDate.Ticks / 10000000L) * 10000000L);
|
||||
|
||||
if (System.DateTime.Compare(d.LastNetworkLogonDate.Value, computerLastLogonDate) < 0)
|
||||
{
|
||||
d.LastNetworkLogonDate = computerLastLogonDate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
d.LastNetworkLogonDate = computerLastLogonDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using Disco.Models.Repository;
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryUserAccountExtensions
|
||||
{
|
||||
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.SamAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.SecurityIdentifier;
|
||||
case "sn":
|
||||
return account.Surname;
|
||||
case "givenname":
|
||||
return account.GivenName;
|
||||
case "mail":
|
||||
return account.Email;
|
||||
case "telephonenumber":
|
||||
return account.Phone;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,16 +29,13 @@ namespace Disco.BI.Interop.Community
|
||||
return string.Format("{0}.{1}.{2:0000}.{3:0000}", v.Major, v.Minor, v.Build, v.Revision);
|
||||
}
|
||||
|
||||
public static UpdateResponse Check(DiscoDataContext Database, bool UseProxy, ScheduledTaskStatus status = null)
|
||||
public static UpdateResponse Check(DiscoDataContext Database, bool UseProxy, IScheduledTaskStatus status)
|
||||
{
|
||||
if (status != null)
|
||||
status.UpdateStatus(10, "Building Update Request");
|
||||
status.UpdateStatus(10, "Building Update Request");
|
||||
|
||||
var request = BuildRequest(Database);
|
||||
//var requestJson = JsonConvert.SerializeObject(request);
|
||||
|
||||
if (status != null)
|
||||
status.UpdateStatus(40, "Sending Request");
|
||||
status.UpdateStatus(40, "Sending Request");
|
||||
|
||||
var DiscoBIVersion = CurrentDiscoVersionFormatted();
|
||||
|
||||
@@ -61,21 +58,18 @@ namespace Disco.BI.Interop.Community
|
||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateRequestV1));
|
||||
xml.Serialize(wrStream, request);
|
||||
}
|
||||
if (status != null)
|
||||
status.UpdateStatus(50, "Waiting for Response");
|
||||
status.UpdateStatus(50, "Waiting for Response");
|
||||
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
|
||||
{
|
||||
if (webResponse.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
if (status != null)
|
||||
status.UpdateStatus(90, "Reading Response");
|
||||
status.UpdateStatus(90, "Reading Response");
|
||||
UpdateResponse result;
|
||||
using (var wResStream = webResponse.GetResponseStream())
|
||||
{
|
||||
XmlSerializer xml = new XmlSerializer(typeof(UpdateResponse));
|
||||
result = (UpdateResponse)xml.Deserialize(wResStream);
|
||||
}
|
||||
//var result = JsonConvert.DeserializeObject<UpdateResponse>(responseContent);
|
||||
Database.DiscoConfiguration.UpdateLastCheck = result;
|
||||
Database.SaveChanges();
|
||||
|
||||
@@ -85,8 +79,7 @@ namespace Disco.BI.Interop.Community
|
||||
}
|
||||
else
|
||||
{
|
||||
if (status != null)
|
||||
status.SetTaskException(new WebException(string.Format("Server responded with: [{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription)));
|
||||
status.SetTaskException(new WebException(string.Format("Server responded with: [{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription)));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.BI.Expressions;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using System.IO;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.Collections.Concurrent;
|
||||
using Disco.BI.Expressions;
|
||||
using System.Collections;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.BI.Expressions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using iTextSharp.text.pdf;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
@@ -65,9 +65,11 @@ namespace Disco.BI.Interop.Pdf
|
||||
DataObjects = new object[DataObjectsIds.Length];
|
||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
||||
{
|
||||
DataObjects[idIndex] = UserService.GetUser(DataObjectsIds[idIndex], Database, true);
|
||||
string dataObjectId = DataObjectsIds[idIndex];
|
||||
|
||||
DataObjects[idIndex] = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(dataObjectId), Database, true);
|
||||
if (DataObjects[idIndex] == null)
|
||||
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
|
||||
throw new Exception(string.Format("Unknown Username specified: {0}", dataObjectId));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -119,10 +121,10 @@ namespace Disco.BI.Interop.Pdf
|
||||
|
||||
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
||||
{
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.Id, TimeStamp);
|
||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.UserId, TimeStamp);
|
||||
if (FlattenFields)
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
||||
else
|
||||
@@ -132,7 +134,7 @@ namespace Disco.BI.Interop.Pdf
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.Id, TimeStamp, pdfFieldPosition.page);
|
||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.UserId, TimeStamp, pdfFieldPosition.page);
|
||||
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
||||
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
||||
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||
@@ -237,7 +239,7 @@ namespace Disco.BI.Interop.Pdf
|
||||
JobLog jl = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = CreatorUser.Id,
|
||||
TechUserId = CreatorUser.UserId,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
|
||||
|
||||
@@ -409,7 +409,7 @@ namespace Disco.BI.Interop.Pdf
|
||||
pdfPagesAssigned.Add(PageNumber, new Tuple<DocumentUniqueIdentifier, byte[]>(docId, pageResult.AttachmentThumbnailImage.ToArray()));
|
||||
|
||||
docId.LoadComponents(Database);
|
||||
DocumentImporterLog.LogImportPageDetected(SessionId, PageNumber, docId.DocumentUniqueId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
||||
DocumentImporterLog.LogImportPageDetected(SessionId, PageNumber, docId.TemplateTypeId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
using Disco.Services.Users;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class AuthorizedPersistentConnection : PersistentConnection
|
||||
{
|
||||
private string authorizedClaim = null;
|
||||
|
||||
protected virtual string AuthorizedClaim { get { return authorizedClaim; } }
|
||||
|
||||
protected override bool AuthorizeRequest(IRequest request)
|
||||
{
|
||||
if (!request.User.Identity.IsAuthenticated)
|
||||
return false;
|
||||
else
|
||||
{
|
||||
var authToken = UserService.CurrentAuthorization;
|
||||
|
||||
if (authToken == null)
|
||||
return false; // No Current User
|
||||
|
||||
if (authorizedClaim == null)
|
||||
return true; // Just Authenticate - no Authorization
|
||||
else
|
||||
return authToken.Has(authorizedClaim);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class HeldDeviceNotifications : PersistentConnection
|
||||
{
|
||||
private static bool subscribed = false;
|
||||
private static object subscribeLock = new object();
|
||||
private static IPersistentConnectionContext notificationContext;
|
||||
|
||||
static HeldDeviceNotifications()
|
||||
{
|
||||
if (!subscribed)
|
||||
lock (subscribeLock)
|
||||
if (!subscribed)
|
||||
{
|
||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<HeldDeviceNotifications>();
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
(e.ModifiedProperties.Contains("Location") ||
|
||||
e.ModifiedProperties.Contains("DeviceModelId") ||
|
||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
||||
e.ModifiedProperties.Contains("ComputerName") ||
|
||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
).Subscribe(DeviceUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(User) &&
|
||||
e.ModifiedProperties.Contains("DisplayName")
|
||||
).Subscribe(UserUpdated);
|
||||
|
||||
subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Job j = (Job)e.Entity;
|
||||
|
||||
if (j.DeviceSerialNumber != null)
|
||||
notificationContext.Connection.Broadcast(j.DeviceSerialNumber);
|
||||
}
|
||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Device d = (Device)e.Entity;
|
||||
|
||||
notificationContext.Connection.Broadcast(d.SerialNumber);
|
||||
}
|
||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
User u = (User)e.Entity;
|
||||
|
||||
var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.Id);
|
||||
|
||||
foreach (var userDevice in userDevices)
|
||||
{
|
||||
notificationContext.Connection.Broadcast(userDevice.SerialNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Logging.Models;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class LogNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
public static bool initialized = false;
|
||||
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public LogNotifications()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
Disco.Services.Logging.Targets.LogLiveContext.LogBroadcast += Broadcast;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
internal static void Broadcast(LogBase logModule, LogEventType eventType, DateTime Timestamp, params object[] Arguments)
|
||||
{
|
||||
var message = LogLiveEvent.Create(logModule, eventType, Timestamp, Arguments);
|
||||
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<LogNotifications>();
|
||||
connectionContext.Groups.Send(_GroupNameAll, message);
|
||||
connectionContext.Groups.Send(logModule.ModuleName, message);
|
||||
}
|
||||
|
||||
private const string _GroupNameAll = "__All";
|
||||
|
||||
public static string AllNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GroupNameAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Services.Authorization;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class RepositoryMonitorNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
RepositoryMonitor.StreamAfterCommit.Subscribe(AfterCommit);
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
private static void AfterCommit(RepositoryMonitorEvent e)
|
||||
{
|
||||
GlobalHost.ConnectionManager.GetConnectionContext<RepositoryMonitorNotifications>().Groups.Send(e.EntityType.Name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Tasks;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class ScheduledTasksStatusNotifications : AuthorizedPersistentConnection
|
||||
{
|
||||
public static bool initialized = false;
|
||||
|
||||
protected override string AuthorizedClaim { get { return Claims.DiscoAdminAccount; } }
|
||||
|
||||
public ScheduledTasksStatusNotifications()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
Disco.Services.Tasks.ScheduledTaskStatus.UpdatedBroadcast += Broadcast;
|
||||
}
|
||||
}
|
||||
|
||||
protected override Task OnConnected(IRequest request, string connectionId)
|
||||
{
|
||||
string addToGroups = request.QueryString["addToGroups"];
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(addToGroups))
|
||||
{
|
||||
var groups = addToGroups.Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnConnected(request, connectionId);
|
||||
}
|
||||
|
||||
protected override System.Threading.Tasks.Task OnReceived(IRequest request, string connectionId, string data)
|
||||
{
|
||||
// Add to Group
|
||||
if (!string.IsNullOrWhiteSpace(data) && data.StartsWith("/addToGroups:") && data.Length > 13)
|
||||
{
|
||||
var groups = data.Substring(13).Split(',');
|
||||
foreach (var g in groups)
|
||||
{
|
||||
this.Groups.Add(connectionId, g);
|
||||
}
|
||||
}
|
||||
return base.OnReceived(request, connectionId, data);
|
||||
}
|
||||
|
||||
internal static void Broadcast(ScheduledTaskStatusLive SessionStatus)
|
||||
{
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<ScheduledTasksStatusNotifications>();
|
||||
connectionContext.Groups.Send(_GroupNameAll, SessionStatus);
|
||||
connectionContext.Groups.Send(SessionStatus.SessionId, SessionStatus);
|
||||
}
|
||||
|
||||
private const string _GroupNameAll = "__All";
|
||||
|
||||
public static string AllNotifications
|
||||
{
|
||||
get
|
||||
{
|
||||
return _GroupNameAll;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.SessionState;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using Owin;
|
||||
using AppFunc = System.Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
/// <summary>
|
||||
/// Required for SignalR 1.1.0 NTLM support in Firefox & Safari
|
||||
/// Returns 401 (Unauthorized) instead of 403 (Forbidden) when an unauthenticated request is processed
|
||||
///
|
||||
/// TODO: Remove this workaround when implementing SignalR 2.x
|
||||
///
|
||||
/// Thanks to David Fowler (@davidfowl)
|
||||
/// </summary>
|
||||
public static class SignalRAuthenticationWorkaround
|
||||
{
|
||||
public static void AddMiddleware(IAppBuilder app)
|
||||
{
|
||||
Func<AppFunc, AppFunc> convert403To401 = Convert403To401;
|
||||
|
||||
app.Use(convert403To401);
|
||||
}
|
||||
|
||||
private static AppFunc Convert403To401(AppFunc next)
|
||||
{
|
||||
return env =>
|
||||
{
|
||||
// Execute the SignalR pipeline
|
||||
Task task = next(env);
|
||||
|
||||
// Get the status code
|
||||
int statusCode = 0;
|
||||
if (env.ContainsKey("owin.ResponseStatusCode"))
|
||||
{
|
||||
statusCode = (int)env["owin.ResponseStatusCode"];
|
||||
}
|
||||
|
||||
// If its 403 then convert it to 401 (we shouldn't do
|
||||
// this if it's a cross domain request since it doesn't make sense)
|
||||
if (statusCode == 403)
|
||||
{
|
||||
env["owin.ResponseStatusCode"] = 401;
|
||||
}
|
||||
|
||||
// Return the original task
|
||||
return task;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.SignalR;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class UserHeldDeviceNotifications : PersistentConnection
|
||||
{
|
||||
private static bool subscribed = false;
|
||||
private static object subscribeLock = new object();
|
||||
private static IPersistentConnectionContext notificationContext;
|
||||
|
||||
static UserHeldDeviceNotifications()
|
||||
{
|
||||
if (!subscribed)
|
||||
lock (subscribeLock)
|
||||
if (!subscribed)
|
||||
{
|
||||
notificationContext = GlobalHost.ConnectionManager.GetConnectionContext<UserHeldDeviceNotifications>();
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e => e.EntityType == typeof(Job)).Subscribe(JobUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
(e.ModifiedProperties.Contains("DeviceModelId") ||
|
||||
e.ModifiedProperties.Contains("DeviceProfileId") ||
|
||||
e.ModifiedProperties.Contains("DeviceBatchId") ||
|
||||
e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
).Subscribe(DeviceUpdated);
|
||||
|
||||
Disco.Data.Repository.Monitor.RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(User) &&
|
||||
e.ModifiedProperties.Contains("DisplayName")
|
||||
).Subscribe(UserUpdated);
|
||||
|
||||
subscribed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private static void JobUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Job j = (Job)e.Entity;
|
||||
|
||||
if (j.DeviceSerialNumber != null)
|
||||
{
|
||||
var jobDevice = e.Database.Devices.Where(d => d.SerialNumber == j.DeviceSerialNumber).FirstOrDefault();
|
||||
|
||||
if (jobDevice.AssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(jobDevice.AssignedUserId);
|
||||
}
|
||||
}
|
||||
private static void DeviceUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
Device d = (Device)e.Entity;
|
||||
|
||||
string previouslyAssignedUserId = null;
|
||||
|
||||
if (e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
previouslyAssignedUserId = e.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
e.ExecuteAfterCommit(me =>
|
||||
{
|
||||
if (previouslyAssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(previouslyAssignedUserId);
|
||||
|
||||
if (d.AssignedUserId != null)
|
||||
notificationContext.Connection.Broadcast(d.AssignedUserId);
|
||||
});
|
||||
}
|
||||
private static void UserUpdated(RepositoryMonitorEvent e)
|
||||
{
|
||||
User u = (User)e.Entity;
|
||||
|
||||
notificationContext.Connection.Broadcast(u.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.BI.Job;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.BI.Extensions;
|
||||
using System.Reactive.Linq;
|
||||
using Disco.Services.Users;
|
||||
|
||||
namespace Disco.BI.JobBI
|
||||
{
|
||||
using FilterFunc = Func<IQueryable<Job>, IQueryable<Job>>;
|
||||
using SortFunc = Func<IEnumerable<Disco.Models.BI.Job.JobTableModel.JobTableItemModel>, IEnumerable<Disco.Models.BI.Job.JobTableModel.JobTableItemModel>>;
|
||||
using Disco.Services.Logging;
|
||||
|
||||
public class ManagedJobList : JobTableModel, IDisposable
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public FilterFunc FilterFunction { get; set; }
|
||||
public SortFunc SortFunction { get; set; }
|
||||
private IDisposable unsubscribeToken;
|
||||
private object updateLock = new object();
|
||||
|
||||
public override List<JobTableItemModel> Items
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.Items.PermissionsFiltered(UserService.CurrentAuthorization);
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new InvalidOperationException("Items cannot be manually set in a Managed Job List");
|
||||
}
|
||||
}
|
||||
|
||||
public ManagedJobList Initialize(DiscoDataContext Database)
|
||||
{
|
||||
// Can only Initialize once
|
||||
if (base.Items != null)
|
||||
return ReInitialize(Database);
|
||||
|
||||
lock (updateLock)
|
||||
{
|
||||
// Subscribe for Changes
|
||||
// - Job (or Job Meta) Changes
|
||||
// - Device Profile Address Changes (for multi-campus Schools)
|
||||
// - Device Model Description Changes
|
||||
// - Device's Profile or Model Changes
|
||||
unsubscribeToken = RepositoryMonitor.StreamAfterCommit
|
||||
.Where(n => n.EntityType == typeof(Job) ||
|
||||
n.EntityType == typeof(JobMetaWarranty) ||
|
||||
n.EntityType == typeof(JobMetaNonWarranty) ||
|
||||
n.EntityType == typeof(JobMetaInsurance) ||
|
||||
(n.EventType == RepositoryMonitorEventType.Modified && (
|
||||
(n.EntityType == typeof(DeviceProfile) && n.ModifiedProperties.Contains("DefaultOrganisationAddress")) ||
|
||||
(n.EntityType == typeof(DeviceModel) && n.ModifiedProperties.Contains("Description")) ||
|
||||
(n.EntityType == typeof(Device) && n.ModifiedProperties.Contains("DeviceProfileId") || n.ModifiedProperties.Contains("DeviceModelId"))
|
||||
)))
|
||||
.Subscribe(JobNotification, NotificationError);
|
||||
|
||||
// Initially fill table
|
||||
base.Items = this.SortFunction(this.DetermineItems(Database, this.FilterFunction(Database.Jobs))).ToList();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public ManagedJobList ReInitialize(DiscoDataContext Database)
|
||||
{
|
||||
return ReInitialize(Database, null, null);
|
||||
}
|
||||
public ManagedJobList ReInitialize(DiscoDataContext Database, FilterFunc FilterFunction)
|
||||
{
|
||||
return ReInitialize(Database, FilterFunction, null);
|
||||
}
|
||||
public ManagedJobList ReInitialize(DiscoDataContext Database, FilterFunc FilterFunction, SortFunc SortFunction)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new ArgumentNullException("Database");
|
||||
|
||||
lock (updateLock)
|
||||
{
|
||||
if (FilterFunction != null)
|
||||
this.FilterFunction = FilterFunction;
|
||||
if (SortFunction != null)
|
||||
this.SortFunction = SortFunction;
|
||||
|
||||
base.Items = this.SortFunction(this.DetermineItems(Database, this.FilterFunction(Database.Jobs))).ToList();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void NotificationError(Exception ex)
|
||||
{
|
||||
SystemLog.LogException(string.Format("Disco.BI.JobBI.ManagedJobList: [{0}]", this.Name), ex);
|
||||
}
|
||||
|
||||
private void JobNotification(RepositoryMonitorEvent e)
|
||||
{
|
||||
List<int> jobIds = null;
|
||||
JobTableItemModel[] existingItems = null;
|
||||
|
||||
if (e.EntityType == typeof(Job))
|
||||
jobIds = new List<int>() { ((Job)e.Entity).Id };
|
||||
else
|
||||
if (e.EntityType == typeof(JobMetaWarranty))
|
||||
jobIds = new List<int>() { ((JobMetaWarranty)e.Entity).JobId };
|
||||
else
|
||||
if (e.EntityType == typeof(JobMetaNonWarranty))
|
||||
jobIds = new List<int>() { ((JobMetaNonWarranty)e.Entity).JobId };
|
||||
else
|
||||
if (e.EntityType == typeof(JobMetaInsurance))
|
||||
jobIds = new List<int>() { ((JobMetaInsurance)e.Entity).JobId };
|
||||
else
|
||||
if (e.EntityType == typeof(DeviceProfile))
|
||||
{
|
||||
int deviceProfileId = ((DeviceProfile)e.Entity).Id;
|
||||
existingItems = base.Items.Where(i => i.DeviceProfileId == deviceProfileId).ToArray();
|
||||
}
|
||||
else
|
||||
if (e.EntityType == typeof(DeviceModel))
|
||||
{
|
||||
int deviceModelId = ((DeviceModel)e.Entity).Id;
|
||||
existingItems = base.Items.Where(i => i.DeviceModelId == deviceModelId).ToArray();
|
||||
}
|
||||
else
|
||||
if (e.EntityType == typeof(Device))
|
||||
{
|
||||
string deviceSerialNumber = ((Device)e.Entity).SerialNumber;
|
||||
existingItems = base.Items.Where(i => i.DeviceSerialNumber == deviceSerialNumber).ToArray();
|
||||
}
|
||||
else
|
||||
return; // Subscription should never reach
|
||||
|
||||
if (jobIds == null)
|
||||
{
|
||||
if (existingItems == null)
|
||||
throw new InvalidOperationException("Notification algorithm didn't indicate any Jobs for update");
|
||||
else
|
||||
jobIds = existingItems.Select(i => i.Id).ToList();
|
||||
}
|
||||
|
||||
if (jobIds.Count == 0)
|
||||
return;
|
||||
else
|
||||
UpdateJobs(e.Database, jobIds, existingItems);
|
||||
}
|
||||
|
||||
private void UpdateJobs(DiscoDataContext Database, List<int> jobIds, JobTableItemModel[] existingItems = null)
|
||||
{
|
||||
lock (updateLock)
|
||||
{
|
||||
// Check for existing items, if not handed them
|
||||
if (existingItems == null)
|
||||
existingItems = base.Items.Where(i => jobIds.Contains(i.Id)).ToArray();
|
||||
|
||||
var updatedItems = this.DetermineItems(Database, this.FilterFunction(Database.Jobs.Where(j => jobIds.Contains(j.Id))));
|
||||
|
||||
var refreshedList = base.Items.ToList();
|
||||
|
||||
// Remove Existing
|
||||
if (existingItems.Length > 0)
|
||||
foreach (var existingItem in existingItems)
|
||||
refreshedList.Remove(existingItem);
|
||||
|
||||
// Add Updated Items
|
||||
if (updatedItems.Count > 0)
|
||||
foreach (var updatedItem in updatedItems)
|
||||
refreshedList.Add(updatedItem);
|
||||
|
||||
// Reorder
|
||||
base.Items = this.SortFunction(refreshedList).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (unsubscribeToken != null)
|
||||
{
|
||||
unsubscribeToken.Dispose();
|
||||
unsubscribeToken = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Job;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.BI.Extensions;
|
||||
|
||||
namespace Disco.BI.JobBI
|
||||
{
|
||||
public static class Searching
|
||||
{
|
||||
public static JobTableModel Search(DiscoDataContext Database, string Term, int? LimitCount = null, bool IncludeJobStatus = true, bool SearchDetails = false)
|
||||
{
|
||||
int termInt = default(int);
|
||||
|
||||
IQueryable<Job> query = default(IQueryable<Job>);
|
||||
|
||||
if (int.TryParse(Term, out termInt))
|
||||
{
|
||||
// Term is a Number (int)
|
||||
if (SearchDetails)
|
||||
{
|
||||
query = BuildJobTableModel(Database).Where(j =>
|
||||
j.Id == termInt ||
|
||||
j.DeviceHeldLocation.Contains(Term) ||
|
||||
j.Device.SerialNumber.Contains(Term) ||
|
||||
j.Device.AssetNumber.Contains(Term) ||
|
||||
j.User.Id == Term ||
|
||||
j.User.Surname.Contains(Term) ||
|
||||
j.User.GivenName.Contains(Term) ||
|
||||
j.User.DisplayName.Contains(Term) ||
|
||||
j.JobLogs.Any(jl => jl.Comments.Contains(Term)) ||
|
||||
j.JobAttachments.Any(ja => ja.Comments.Contains(Term)));
|
||||
}
|
||||
else
|
||||
{
|
||||
query = BuildJobTableModel(Database).Where(j =>
|
||||
j.Id == termInt ||
|
||||
j.DeviceHeldLocation.Contains(Term) ||
|
||||
j.Device.SerialNumber.Contains(Term) ||
|
||||
j.Device.AssetNumber.Contains(Term) ||
|
||||
j.User.Id == Term ||
|
||||
j.User.Surname.Contains(Term) ||
|
||||
j.User.GivenName.Contains(Term) ||
|
||||
j.User.DisplayName.Contains(Term));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SearchDetails)
|
||||
{
|
||||
query = BuildJobTableModel(Database).Where(j =>
|
||||
j.DeviceHeldLocation.Contains(Term) ||
|
||||
j.Device.SerialNumber.Contains(Term) ||
|
||||
j.Device.AssetNumber.Contains(Term) ||
|
||||
j.User.Id == Term ||
|
||||
j.User.Surname.Contains(Term) ||
|
||||
j.User.GivenName.Contains(Term) ||
|
||||
j.User.DisplayName.Contains(Term) ||
|
||||
j.JobLogs.Any(jl => jl.Comments.Contains(Term)) ||
|
||||
j.JobAttachments.Any(ja => ja.Comments.Contains(Term)));
|
||||
}
|
||||
else
|
||||
{
|
||||
query = BuildJobTableModel(Database).Where(j =>
|
||||
j.DeviceHeldLocation.Contains(Term) ||
|
||||
j.Device.SerialNumber.Contains(Term) ||
|
||||
j.Device.AssetNumber.Contains(Term) ||
|
||||
j.User.Id == Term ||
|
||||
j.User.Surname.Contains(Term) ||
|
||||
j.User.GivenName.Contains(Term) ||
|
||||
j.User.DisplayName.Contains(Term));
|
||||
}
|
||||
}
|
||||
|
||||
if (LimitCount.HasValue)
|
||||
query = query.Take(LimitCount.Value);
|
||||
|
||||
JobTableModel model = new JobTableModel() { ShowStatus = IncludeJobStatus };
|
||||
model.Fill(Database, query);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public static IQueryable<Job> BuildJobTableModel(DiscoDataContext Database)
|
||||
{
|
||||
return Database.Jobs.Include("JobType").Include("Device").Include("User").Include("OpenedTechUser");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ namespace Disco.BI.JobBI.Statistics
|
||||
public override string TaskName { get { return "Job Statistics - Daily Opened/Closed Task"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
@@ -100,7 +101,6 @@ namespace Disco.BI.JobBI.Statistics
|
||||
else
|
||||
{
|
||||
DateTime? previousValue = e.GetPreviousPropertyValue<DateTime?>("ClosedDate");
|
||||
DateTime? currentValue = e.GetCurrentPropertyValue<DateTime?>("ClosedDate");
|
||||
|
||||
if (previousValue.HasValue)
|
||||
{
|
||||
@@ -116,21 +116,23 @@ namespace Disco.BI.JobBI.Statistics
|
||||
affectedStat.TotalJobs += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentValue.HasValue)
|
||||
DateTime? currentValue = e.GetCurrentPropertyValue<DateTime?>("ClosedDate");
|
||||
|
||||
if (currentValue.HasValue)
|
||||
{
|
||||
// Add Statistics
|
||||
// Remove Statistics
|
||||
var statItem = _data.FirstOrDefault(i => i.Timestamp == currentValue.Value.Date);
|
||||
if (statItem != null)
|
||||
{
|
||||
// Add Statistics
|
||||
// Remove Statistics
|
||||
var statItem = _data.FirstOrDefault(i => i.Timestamp == currentValue.Value.Date);
|
||||
if (statItem != null)
|
||||
{
|
||||
statItem.ClosedJobs += 1;
|
||||
statItem.TotalJobs -= 1;
|
||||
}
|
||||
foreach (var affectedStat in _data.Where(i => i.Timestamp > currentValue))
|
||||
{
|
||||
affectedStat.TotalJobs -= 1;
|
||||
}
|
||||
statItem.ClosedJobs += 1;
|
||||
statItem.TotalJobs -= 1;
|
||||
}
|
||||
foreach (var affectedStat in _data.Where(i => i.Timestamp > currentValue))
|
||||
{
|
||||
affectedStat.TotalJobs -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ namespace Disco.BI.JobBI
|
||||
{
|
||||
public static class Utilities
|
||||
{
|
||||
public static Job Create(DiscoDataContext Database, Device device, User user, JobType type, List<JobSubType> subTypes, User initialTech)
|
||||
public static Job Create(DiscoDataContext Database, Device device, User user, JobType type, List<JobSubType> subTypes, User initialTech, bool addAutoQueues = true)
|
||||
{
|
||||
Job j = new Job()
|
||||
{
|
||||
JobType = type,
|
||||
OpenedTechUserId = initialTech.Id,
|
||||
OpenedTechUserId = initialTech.UserId,
|
||||
OpenedTechUser = initialTech,
|
||||
OpenedDate = DateTime.Now
|
||||
};
|
||||
@@ -31,7 +31,7 @@ namespace Disco.BI.JobBI
|
||||
if (user != null)
|
||||
{
|
||||
j.User = user;
|
||||
j.UserId = user.Id;
|
||||
j.UserId = user.UserId;
|
||||
}
|
||||
|
||||
// Sub Types
|
||||
@@ -40,6 +40,36 @@ namespace Disco.BI.JobBI
|
||||
|
||||
Database.Jobs.Add(j);
|
||||
|
||||
// Job Queues
|
||||
if (addAutoQueues)
|
||||
{
|
||||
var queues = from st in subTypes
|
||||
from jq in st.JobQueues
|
||||
group st by jq into g
|
||||
select new { queue = g.Key, subTypes = g };
|
||||
foreach (var queue in queues)
|
||||
{
|
||||
var commentBuilder = new StringBuilder("Automatically added by:").AppendLine();
|
||||
foreach (var subType in queue.subTypes)
|
||||
{
|
||||
commentBuilder.AppendLine().Append("* ").Append(subType.Description);
|
||||
}
|
||||
|
||||
var jqj = new JobQueueJob()
|
||||
{
|
||||
JobQueueId = queue.queue.Id,
|
||||
Job = j,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = initialTech.UserId,
|
||||
AddedComment = commentBuilder.ToString(),
|
||||
SLAExpiresDate = queue.queue.DefaultSLAExpiry.HasValue ? (DateTime?)DateTime.Now.AddMinutes(queue.queue.DefaultSLAExpiry.Value) : null,
|
||||
Priority = JobQueuePriority.Normal
|
||||
};
|
||||
|
||||
Database.JobQueueJobs.Add(jqj);
|
||||
}
|
||||
}
|
||||
|
||||
switch (type.Id)
|
||||
{
|
||||
case JobType.JobTypeIds.HWar:
|
||||
@@ -79,7 +109,7 @@ namespace Disco.BI.JobBI
|
||||
Database.JobComponents.Add(new JobComponent()
|
||||
{
|
||||
Job = j,
|
||||
TechUserId = initialTech.Id,
|
||||
TechUserId = initialTech.UserId,
|
||||
Cost = c.Cost,
|
||||
Description = c.Description
|
||||
});
|
||||
@@ -89,83 +119,5 @@ namespace Disco.BI.JobBI
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
public static string JobStatusDescription(string StatusId, Job j = null)
|
||||
{
|
||||
switch (StatusId)
|
||||
{
|
||||
case Job.JobStatusIds.Open:
|
||||
return "Open";
|
||||
case Job.JobStatusIds.Closed:
|
||||
return "Closed";
|
||||
case Job.JobStatusIds.AwaitingWarrantyRepair:
|
||||
if (j == null)
|
||||
return "Awaiting Warranty Repair";
|
||||
else
|
||||
if (j.DeviceHeld.HasValue)
|
||||
return string.Format("Awaiting Warranty Repair ({0})", j.JobMetaWarranty.ExternalName);
|
||||
else
|
||||
return string.Format("Awaiting Warranty Repair - Not Held ({0})", j.JobMetaWarranty.ExternalName);
|
||||
case Job.JobStatusIds.AwaitingRepairs:
|
||||
if (j == null)
|
||||
return "Awaiting Repairs";
|
||||
else
|
||||
if (j.DeviceHeld.HasValue)
|
||||
return string.Format("Awaiting Repairs ({0})", j.JobMetaNonWarranty.RepairerName);
|
||||
else
|
||||
return string.Format("Awaiting Repairs - Not Held ({0})", j.JobMetaNonWarranty.RepairerName);
|
||||
case Job.JobStatusIds.AwaitingDeviceReturn:
|
||||
return "Awaiting Device Return";
|
||||
case Job.JobStatusIds.AwaitingUserAction:
|
||||
return "Awaiting User Action";
|
||||
case Job.JobStatusIds.AwaitingAccountingPayment:
|
||||
return "Awaiting Accounting Payment";
|
||||
case Job.JobStatusIds.AwaitingAccountingCharge:
|
||||
return "Awaiting Accounting Charge";
|
||||
case Job.JobStatusIds.AwaitingInsuranceProcessing:
|
||||
return "Awaiting Insurance Processing";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
public static string JobStatusDescription(string StatusId, JobTableModel.JobTableItemModelIncludeStatus j = null)
|
||||
{
|
||||
switch (StatusId)
|
||||
{
|
||||
case Job.JobStatusIds.Open:
|
||||
return "Open";
|
||||
case Job.JobStatusIds.Closed:
|
||||
return "Closed";
|
||||
case Job.JobStatusIds.AwaitingWarrantyRepair:
|
||||
if (j == null)
|
||||
return "Awaiting Warranty Repair";
|
||||
else
|
||||
if (j.DeviceHeld.HasValue)
|
||||
return string.Format("Awaiting Warranty Repair ({0})", j.JobMetaWarranty_ExternalName);
|
||||
else
|
||||
return string.Format("Awaiting Warranty Repair - Not Held ({0})", j.JobMetaWarranty_ExternalName);
|
||||
case Job.JobStatusIds.AwaitingRepairs:
|
||||
if (j == null)
|
||||
return "Awaiting Repairs";
|
||||
else
|
||||
if (j.DeviceHeld.HasValue)
|
||||
return string.Format("Awaiting Repairs ({0})", j.JobMetaNonWarranty_RepairerName);
|
||||
else
|
||||
return string.Format("Awaiting Repairs - Not Held ({0})", j.JobMetaNonWarranty_RepairerName);
|
||||
case Job.JobStatusIds.AwaitingDeviceReturn:
|
||||
return "Awaiting Device Return";
|
||||
case Job.JobStatusIds.AwaitingUserAction:
|
||||
return "Awaiting User Action";
|
||||
case Job.JobStatusIds.AwaitingAccountingPayment:
|
||||
return "Awaiting Accounting Payment";
|
||||
case Job.JobStatusIds.AwaitingAccountingCharge:
|
||||
return "Awaiting Accounting Charge";
|
||||
case Job.JobStatusIds.AwaitingInsuranceProcessing:
|
||||
return "Awaiting Insurance Processing";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Search;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Users;
|
||||
|
||||
namespace Disco.BI.UserBI
|
||||
{
|
||||
public static class Searching
|
||||
{
|
||||
|
||||
public static List<User> SearchUpstream(string Term)
|
||||
{
|
||||
return Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term).Select(adU => adU.ToRepositoryUser()).ToList();
|
||||
}
|
||||
|
||||
private static List<UserSearchResultItem> Search_SelectUserSearchResultItems(IQueryable<User> Query, int? LimitCount = null)
|
||||
{
|
||||
if (LimitCount.HasValue)
|
||||
Query = Query.Take(LimitCount.Value);
|
||||
|
||||
return Query.Select(u => new UserSearchResultItem()
|
||||
{
|
||||
Id = u.Id,
|
||||
Surname = u.Surname,
|
||||
GivenName = u.GivenName,
|
||||
DisplayName = u.DisplayName,
|
||||
AssignedDevicesCount = u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue).Count(),
|
||||
JobCount = u.Jobs.Count()
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
public static List<UserSearchResultItem> Search(DiscoDataContext Database, string Term, int? LimitCount = null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Term) || Term.Length < 2)
|
||||
throw new ArgumentException("Search Term must contain at least two characters", "Term");
|
||||
|
||||
// Search Active Directory & Import Relevant Users
|
||||
var adImportedUsers = Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term).Select(adU => adU.ToRepositoryUser());
|
||||
foreach (var adU in adImportedUsers)
|
||||
{
|
||||
var existingUser = Database.Users.Find(adU.Id);
|
||||
if (existingUser != null)
|
||||
existingUser.UpdateSelf(adU);
|
||||
else
|
||||
Database.Users.Add(adU);
|
||||
Database.SaveChanges();
|
||||
UserService.InvalidateCachedUser(adU.Id);
|
||||
}
|
||||
|
||||
return Search_SelectUserSearchResultItems(Database.Users.Where(u =>
|
||||
u.Id.Contains(Term) ||
|
||||
u.Surname.Contains(Term) ||
|
||||
u.GivenName.Contains(Term) ||
|
||||
u.DisplayName.Contains(Term)
|
||||
), LimitCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
-63
@@ -46,36 +46,6 @@
|
||||
<Reference Include="itextsharp">
|
||||
<HintPath>..\Resources\Libraries\iTextSharp\itextsharp.dll</HintPath>
|
||||
</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">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Core.1.1.2\lib\net40\Microsoft.AspNet.SignalR.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.Owin, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.Owin.1.1.2\lib\net45\Microsoft.AspNet.SignalR.Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.AspNet.SignalR.SystemWeb, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Microsoft.AspNet.SignalR.SystemWeb.1.1.2\lib\net45\Microsoft.AspNet.SignalR.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Owin.Host.SystemWeb">
|
||||
<HintPath>..\packages\Microsoft.Owin.Host.SystemWeb.1.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Owin">
|
||||
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Quartz">
|
||||
<HintPath>..\Resources\Libraries\Quartz\Quartz.dll</HintPath>
|
||||
</Reference>
|
||||
@@ -89,20 +59,21 @@
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Reactive.Core, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Reactive.Core, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
|
||||
<HintPath>..\packages\Rx-Core.2.2.4\lib\net45\System.Reactive.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.Interfaces, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Reactive.Interfaces, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
|
||||
<HintPath>..\packages\Rx-Interfaces.2.2.4\lib\net45\System.Reactive.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.Linq, Version=2.1.30214.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<Reference Include="System.Reactive.Linq, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll</HintPath>
|
||||
<HintPath>..\packages\Rx-Linq.2.2.4\lib\net45\System.Reactive.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.PlatformServices">
|
||||
<HintPath>..\packages\Rx-PlatformServices.2.1.30214.0\lib\Net45\System.Reactive.PlatformServices.dll</HintPath>
|
||||
<Reference Include="System.Reactive.PlatformServices, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-PlatformServices.2.2.4\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
@@ -124,14 +95,12 @@
|
||||
<Compile Include="BI\AttachmentBI\Utilities.cs" />
|
||||
<Compile Include="BI\DeviceBI\BatchUtilities.cs" />
|
||||
<Compile Include="BI\DeviceBI\DeviceModelBI.cs" />
|
||||
<Compile Include="BI\DeviceBI\Importing\Export.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\Searching.cs" />
|
||||
<Compile Include="BI\DisposableImageCollection.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateDevicesManagedGroup.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateManagedGroups.cs" />
|
||||
<Compile Include="BI\Expressions\EvaluateExpressionParseException.cs" />
|
||||
<Compile Include="BI\Expressions\ExpressionCachePreloadTask.cs" />
|
||||
<Compile Include="BI\Expressions\Extensions\DataExt.cs" />
|
||||
@@ -146,6 +115,7 @@
|
||||
<Compile Include="BI\Extensions\AttachmentExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\AuthorizationRoleExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\ClientServicesExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\UserFlagActionExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\DeviceActionExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\DeviceBatchExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\DeviceCertificateExtensions.cs" />
|
||||
@@ -155,7 +125,7 @@
|
||||
<Compile Include="BI\Extensions\JobActionExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\JobExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\JobFlagExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\JobTableExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\JobQueueActionExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\UserExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\WirelessCertificateExtensions.cs" />
|
||||
<Compile Include="BI\Extensions\DeviceExtensions.cs" />
|
||||
@@ -175,32 +145,14 @@
|
||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterJob.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterCleanCacheJob.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\Importer\DocumentImporterLog.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectory.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryCachedGroups.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryGroupExtensions.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryHelpers.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryMachineAccountExtensions.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryOrganisationalUnit.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUpdateLastNetworkLogonDateJob.cs" />
|
||||
<Compile Include="BI\Interop\ActiveDirectory\ActiveDirectoryUserAccountExtensions.cs" />
|
||||
<Compile Include="BI\Expressions\ExpressionCache.cs" />
|
||||
<Compile Include="BI\Interop\Community\UpdateCheck.cs" />
|
||||
<Compile Include="BI\Interop\Community\UpdateCheckTask.cs" />
|
||||
<Compile Include="BI\Interop\MimeTypes.cs" />
|
||||
<Compile Include="BI\Interop\Pdf\PdfGenerator.cs" />
|
||||
<Compile Include="BI\Interop\Pdf\PdfImporter.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\AuthorizedPersistentConnection.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\HeldDeviceNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\LogNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\RepositoryMonitorNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\ScheduledTasksStatusNotifications.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\SignalRAuthenticationWorkaround.cs" />
|
||||
<Compile Include="BI\Interop\SignalRHandlers\UserHeldDeviceNotifications.cs" />
|
||||
<Compile Include="BI\JobBI\ManagedJobList.cs" />
|
||||
<Compile Include="BI\JobBI\Searching.cs" />
|
||||
<Compile Include="BI\JobBI\Statistics\DailyOpenedClosed.cs" />
|
||||
<Compile Include="BI\JobBI\Utilities.cs" />
|
||||
<Compile Include="BI\UserBI\Searching.cs" />
|
||||
<Compile Include="BI\Extensions\UtilityExtensions.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
@@ -255,7 +207,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<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_StartDate="2014/6/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyFileVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyVersion("2.0.0626.0000")]
|
||||
[assembly: AssemblyFileVersion("2.0.0626.0000")]
|
||||
@@ -18,4 +18,28 @@
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
@@ -1,16 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="EntityFramework" version="5.0.0" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Core" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.Owin" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.AspNet.SignalR.SystemWeb" version="1.1.2" targetFramework="net45" />
|
||||
<package id="Microsoft.Owin.Host.SystemWeb" version="1.0.1" targetFramework="net45" />
|
||||
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" />
|
||||
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net45" />
|
||||
<package id="Owin" version="1.0" targetFramework="net45" />
|
||||
<package id="Rx-Core" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Interfaces" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Linq" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Main" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-PlatformServices" version="2.1.30214.0" targetFramework="net45" />
|
||||
<package id="Rx-Core" version="2.2.4" targetFramework="net45" />
|
||||
<package id="Rx-Interfaces" version="2.2.4" targetFramework="net45" />
|
||||
<package id="Rx-Linq" version="2.2.4" targetFramework="net45" />
|
||||
<package id="Rx-Main" version="2.2.4" targetFramework="net45" />
|
||||
<package id="Rx-PlatformServices" version="2.2.4" targetFramework="net45" />
|
||||
</packages>
|
||||
@@ -48,9 +48,8 @@
|
||||
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.3\lib\net40\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
@@ -122,7 +121,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2014/6/1" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Disco.Client.Extensions
|
||||
enrol.DeviceModelType = Interop.SystemAudit.DeviceType;
|
||||
|
||||
enrol.DeviceIsPartOfDomain = Interop.SystemAudit.DeviceIsPartOfDomain;
|
||||
enrol.DeviceDNSDomainName = Interop.SystemAudit.DeviceDNSDomainName;
|
||||
|
||||
// LAN
|
||||
enrol.DeviceLanMacAddress = Interop.Network.PrimaryLanMacAddress;
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 32 KiB |
@@ -22,8 +22,8 @@ namespace Disco.Client.Interop
|
||||
using (DirectoryEntry member = new DirectoryEntry(memberRef))
|
||||
{
|
||||
var memberPath = member.Path;
|
||||
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.InvariantCultureIgnoreCase) ||
|
||||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.InvariantCultureIgnoreCase))
|
||||
if (memberPath.Equals(string.Format("WinNT://{0}/{1}", UserDomain, Username), StringComparison.OrdinalIgnoreCase) ||
|
||||
memberPath.Equals(string.Format("WinNT://{0}", UserSID), StringComparison.OrdinalIgnoreCase))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Disco.Client.Interop
|
||||
// Determine Primary Adapters
|
||||
|
||||
// Lan
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.InvariantCultureIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter && n.NetConnectionId.StartsWith("Local Area Connection", StringComparison.OrdinalIgnoreCase)).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
// Might be too restrictive - remove name restriction just in case.
|
||||
if (PrimaryLanNetworkAdapter == null)
|
||||
PrimaryLanNetworkAdapter = NetworkAdapters.Where(n => !n.IsWLanAdapter).OrderByDescending(n => n.Speed).FirstOrDefault();
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Disco.Client.Interop
|
||||
public static string DeviceType { get; private set; }
|
||||
public static string DeviceUUID { get; private set; }
|
||||
public static bool DeviceIsPartOfDomain { get; private set; }
|
||||
public static string DeviceDNSDomainName { get; private set; }
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
@@ -56,7 +57,7 @@ namespace Disco.Client.Interop
|
||||
// Get System Information
|
||||
try
|
||||
{
|
||||
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Manufacturer, Model, PartOfDomain, PCSystemType FROM Win32_ComputerSystem"))
|
||||
using (ManagementObjectSearcher mSearcher = new ManagementObjectSearcher("SELECT Manufacturer, Model, PartOfDomain, PCSystemType, Domain FROM Win32_ComputerSystem"))
|
||||
{
|
||||
using (ManagementObjectCollection mResults = mSearcher.Get())
|
||||
{
|
||||
@@ -74,6 +75,8 @@ namespace Disco.Client.Interop
|
||||
|
||||
DeviceIsPartOfDomain = (bool)mItem.GetPropertyValue("PartOfDomain");
|
||||
DeviceType = PCSystemTypeToString((UInt16)mItem.GetPropertyValue("PCSystemType"));
|
||||
|
||||
DeviceDNSDomainName = DeviceIsPartOfDomain ? mItem.GetPropertyValue("Domain") as string : null;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -124,9 +127,9 @@ namespace Disco.Client.Interop
|
||||
// Added 2012-11-22 G# - Lenovo IdeaPad Serial SHIM
|
||||
// http://www.discoict.com.au/forum/feature-requests/2012/11/serial-number-detection-on-ideapads.aspx
|
||||
if (string.IsNullOrWhiteSpace(DeviceSerialNumber) ||
|
||||
(DeviceManufacturer.Equals("LENOVO", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
(DeviceModel.Equals("S10-3", StringComparison.InvariantCultureIgnoreCase) // S10-3
|
||||
|| DeviceModel.Equals("2957", StringComparison.InvariantCultureIgnoreCase)))) // S10-2
|
||||
(DeviceManufacturer.Equals("LENOVO", StringComparison.OrdinalIgnoreCase) &&
|
||||
(DeviceModel.Equals("S10-3", StringComparison.OrdinalIgnoreCase) // S10-3
|
||||
|| DeviceModel.Equals("2957", StringComparison.OrdinalIgnoreCase)))) // S10-2
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyFileVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyVersion("2.0.0626.0000")]
|
||||
[assembly: AssemblyFileVersion("2.0.0626.0000")]
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="Newtonsoft.Json" version="5.0.8" targetFramework="net40-Client" />
|
||||
<package id="Newtonsoft.Json" version="6.0.3" targetFramework="net40-Client" />
|
||||
</packages>
|
||||
@@ -319,7 +319,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" />
|
||||
<UserProperties BuildVersion_StartDate="2014/6/1" BuildVersion_DetectChanges="False" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 32 KiB |
@@ -74,14 +74,14 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
// Only Copy Certain Files
|
||||
|
||||
// Copy Wireless Certificates
|
||||
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (fileName.StartsWith("WLAN_Cert_Root_", StringComparison.OrdinalIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Intermediate_", StringComparison.OrdinalIgnoreCase) ||
|
||||
fileName.StartsWith("WLAN_Cert_Personal_", StringComparison.OrdinalIgnoreCase))
|
||||
File.Copy(file, Path.Combine(InstallLocation, fileName));
|
||||
|
||||
// Copy Wireless Profiles
|
||||
if (fileName.StartsWith("WLAN_Profile_", StringComparison.InvariantCultureIgnoreCase) &&
|
||||
fileName.EndsWith(".xml", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (fileName.StartsWith("WLAN_Profile_", StringComparison.OrdinalIgnoreCase) &&
|
||||
fileName.EndsWith(".xml", StringComparison.OrdinalIgnoreCase))
|
||||
File.Copy(file, Path.Combine(InstallLocation, fileName));
|
||||
|
||||
}
|
||||
@@ -194,7 +194,7 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
if (string.IsNullOrWhiteSpace(InstallLocation))
|
||||
InstallLocation = Path.Combine(Path.GetPathRoot(Environment.SystemDirectory), "Disco");
|
||||
|
||||
if (InstallLocation.EndsWith(".wim", StringComparison.InvariantCultureIgnoreCase))
|
||||
if (InstallLocation.EndsWith(".wim", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Offline File System (WIM)
|
||||
Program.Status.UpdateStatus("Installing Bootstrapper (Offline)", "Installing", string.Format("Install Location: {0}", InstallLocation));
|
||||
@@ -216,7 +216,7 @@ namespace Disco.ClientBootstrapper.Interop
|
||||
using (var wimImage = wim[i])
|
||||
wimImageInfo.LoadXml(wimImage.ImageInformation);
|
||||
var wimImageInfoName = wimImageInfo.SelectSingleNode("//IMAGE/NAME");
|
||||
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.InvariantCultureIgnoreCase))
|
||||
if (wimImageInfoName != null && wimImageInfoName.InnerText.Equals(WimImageId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
wimImageIndex = i + 1;
|
||||
Program.Status.UpdateStatus(null, "Analysing WIM", string.Format("Found Image Id '{0}' at Index {1}", WimImageId, wimImageIndex));
|
||||
|
||||
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyFileVersion("1.2.1128.1503")]
|
||||
[assembly: AssemblyVersion("2.0.0626.0000")]
|
||||
[assembly: AssemblyFileVersion("2.0.0626.0000")]
|
||||
@@ -1,116 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProductVersion>
|
||||
</ProductVersion>
|
||||
<SchemaVersion>
|
||||
</SchemaVersion>
|
||||
<ProjectGuid>{CD7BB28C-B74D-4880-8B7E-4487AB5E6AFC}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>Disco.Configuration</RootNamespace>
|
||||
<AssemblyName>Disco.Configuration</AssemblyName>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<MyType>Windows</MyType>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DocumentationFile>Disco.Configuration.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DocumentationFile>Disco.Configuration.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionExplicit>On</OptionExplicit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionCompare>Binary</OptionCompare>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionStrict>Off</OptionStrict>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<OptionInfer>On</OptionInfer>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Import Include="Microsoft.VisualBasic" />
|
||||
<Import Include="System" />
|
||||
<Import Include="System.Collections" />
|
||||
<Import Include="System.Collections.Generic" />
|
||||
<Import Include="System.Data" />
|
||||
<Import Include="System.Diagnostics" />
|
||||
<Import Include="System.Linq" />
|
||||
<Import Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="My Project\AssemblyInfo.vb" />
|
||||
<Compile Include="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="My Project\Resources.resx">
|
||||
<Generator>VbMyResourcesResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.vb</LastGenOutput>
|
||||
<CustomToolNamespace>My.Resources</CustomToolNamespace>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
<None Include="My Project\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<CustomToolNamespace>My</CustomToolNamespace>
|
||||
<LastGenOutput>Settings.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Disco.Models\Disco.Models.vbproj">
|
||||
<Project>{40F222A9-CC05-4035-AFF4-15A78250EF2B}</Project>
|
||||
<Name>Disco.Models</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.VisualBasic.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,13 +0,0 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.235
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<MyApplicationData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<MySubMain>false</MySubMain>
|
||||
<SingleInstance>false</SingleInstance>
|
||||
<ShutdownMode>0</ShutdownMode>
|
||||
<EnableVisualStyles>true</EnableVisualStyles>
|
||||
<AuthenticationMode>0</AuthenticationMode>
|
||||
<ApplicationType>1</ApplicationType>
|
||||
<SaveMySettingsOnExit>true</SaveMySettingsOnExit>
|
||||
</MyApplicationData>
|
||||
@@ -1,35 +0,0 @@
|
||||
Imports System
|
||||
Imports System.Reflection
|
||||
Imports System.Runtime.InteropServices
|
||||
|
||||
' General Information about an assembly is controlled through the following
|
||||
' set of attributes. Change these attribute values to modify the information
|
||||
' associated with an assembly.
|
||||
|
||||
' Review the values of the assembly attributes
|
||||
|
||||
<Assembly: AssemblyTitle("Disco - Configuration")>
|
||||
<Assembly: AssemblyDescription("")>
|
||||
<Assembly: AssemblyCompany("")>
|
||||
<Assembly: AssemblyProduct("Disco")>
|
||||
<Assembly: AssemblyCopyright("")>
|
||||
<Assembly: AssemblyTrademark("")>
|
||||
|
||||
<Assembly: ComVisible(False)>
|
||||
|
||||
'The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
<Assembly: Guid("535f903b-6111-4adb-b200-9df78e49d13b")>
|
||||
|
||||
' Version information for an assembly consists of the following four values:
|
||||
'
|
||||
' Major Version
|
||||
' Minor Version
|
||||
' Build Number
|
||||
' Revision
|
||||
'
|
||||
' You can specify all the values or you can default the Build and Revision Numbers
|
||||
' by using the '*' as shown below:
|
||||
' <Assembly: AssemblyVersion("1.0.*")>
|
||||
|
||||
<Assembly: AssemblyVersion("1.0.0.0")>
|
||||
<Assembly: AssemblyFileVersion("1.0.0.0")>
|
||||
@@ -1,62 +0,0 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.235
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My.Resources
|
||||
|
||||
'This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
'class via a tool like ResGen or Visual Studio.
|
||||
'To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
'with the /str option, or rebuild your VS project.
|
||||
'''<summary>
|
||||
''' A strongly-typed resource class, for looking up localized strings, etc.
|
||||
'''</summary>
|
||||
<Global.System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0"), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.Microsoft.VisualBasic.HideModuleNameAttribute()> _
|
||||
Friend Module Resources
|
||||
|
||||
Private resourceMan As Global.System.Resources.ResourceManager
|
||||
|
||||
Private resourceCulture As Global.System.Globalization.CultureInfo
|
||||
|
||||
'''<summary>
|
||||
''' Returns the cached ResourceManager instance used by this class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend ReadOnly Property ResourceManager() As Global.System.Resources.ResourceManager
|
||||
Get
|
||||
If Object.ReferenceEquals(resourceMan, Nothing) Then
|
||||
Dim temp As Global.System.Resources.ResourceManager = New Global.System.Resources.ResourceManager("Disco.Configuration.Resources", GetType(Resources).Assembly)
|
||||
resourceMan = temp
|
||||
End If
|
||||
Return resourceMan
|
||||
End Get
|
||||
End Property
|
||||
|
||||
'''<summary>
|
||||
''' Overrides the current thread's CurrentUICulture property for all
|
||||
''' resource lookups using this strongly typed resource class.
|
||||
'''</summary>
|
||||
<Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Friend Property Culture() As Global.System.Globalization.CultureInfo
|
||||
Get
|
||||
Return resourceCulture
|
||||
End Get
|
||||
Set(ByVal value As Global.System.Globalization.CultureInfo)
|
||||
resourceCulture = value
|
||||
End Set
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
@@ -1,117 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
'------------------------------------------------------------------------------
|
||||
' <auto-generated>
|
||||
' This code was generated by a tool.
|
||||
' Runtime Version:4.0.30319.235
|
||||
'
|
||||
' Changes to this file may cause incorrect behavior and will be lost if
|
||||
' the code is regenerated.
|
||||
' </auto-generated>
|
||||
'------------------------------------------------------------------------------
|
||||
|
||||
Option Strict On
|
||||
Option Explicit On
|
||||
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute(), _
|
||||
Global.System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0"), _
|
||||
Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Partial Friend NotInheritable Class MySettings
|
||||
Inherits Global.System.Configuration.ApplicationSettingsBase
|
||||
|
||||
Private Shared defaultInstance As MySettings = CType(Global.System.Configuration.ApplicationSettingsBase.Synchronized(New MySettings), MySettings)
|
||||
|
||||
#Region "My.Settings Auto-Save Functionality"
|
||||
#If _MyType = "WindowsForms" Then
|
||||
Private Shared addedHandler As Boolean
|
||||
|
||||
Private Shared addedHandlerLockObject As New Object
|
||||
|
||||
<Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), Global.System.ComponentModel.EditorBrowsableAttribute(Global.System.ComponentModel.EditorBrowsableState.Advanced)> _
|
||||
Private Shared Sub AutoSaveSettings(ByVal sender As Global.System.Object, ByVal e As Global.System.EventArgs)
|
||||
If My.Application.SaveMySettingsOnExit Then
|
||||
My.Settings.Save()
|
||||
End If
|
||||
End Sub
|
||||
#End If
|
||||
#End Region
|
||||
|
||||
Public Shared ReadOnly Property [Default]() As MySettings
|
||||
Get
|
||||
|
||||
#If _MyType = "WindowsForms" Then
|
||||
If Not addedHandler Then
|
||||
SyncLock addedHandlerLockObject
|
||||
If Not addedHandler Then
|
||||
AddHandler My.Application.Shutdown, AddressOf AutoSaveSettings
|
||||
addedHandler = True
|
||||
End If
|
||||
End SyncLock
|
||||
End If
|
||||
#End If
|
||||
Return defaultInstance
|
||||
End Get
|
||||
End Property
|
||||
End Class
|
||||
End Namespace
|
||||
|
||||
Namespace My
|
||||
|
||||
<Global.Microsoft.VisualBasic.HideModuleNameAttribute(), _
|
||||
Global.System.Diagnostics.DebuggerNonUserCodeAttribute(), _
|
||||
Global.System.Runtime.CompilerServices.CompilerGeneratedAttribute()> _
|
||||
Friend Module MySettingsProperty
|
||||
|
||||
<Global.System.ComponentModel.Design.HelpKeywordAttribute("My.Settings")> _
|
||||
Friend ReadOnly Property Settings() As Global.Disco.Configuration.My.MySettings
|
||||
Get
|
||||
Return Global.Disco.Configuration.My.MySettings.Default
|
||||
End Get
|
||||
End Property
|
||||
End Module
|
||||
End Namespace
|
||||
@@ -1,7 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" UseMySettingsClassName="true">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
@@ -15,29 +11,37 @@ namespace Disco.Data.Configuration
|
||||
|
||||
public abstract string Scope { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a read-write configuration instance
|
||||
/// </summary>
|
||||
public ConfigurationBase(DiscoDataContext Database)
|
||||
{
|
||||
this.Database = Database;
|
||||
}
|
||||
|
||||
protected List<ConfigurationItem> Items
|
||||
/// <summary>
|
||||
/// Creates a read-only configuration instance
|
||||
/// </summary>
|
||||
public ConfigurationBase() : this(null) { }
|
||||
|
||||
protected IEnumerable<string> ItemKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationCache.GetConfigurationItems(Database, this.Scope);
|
||||
return ConfigurationCache.GetScopeKeys(Database, this.Scope);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValue<ValueType>(string Key, ValueType Value)
|
||||
private void SetValue<T>(string Key, T Value)
|
||||
{
|
||||
ConfigurationCache.SetConfigurationValue(Database, this.Scope, Key, Value);
|
||||
ConfigurationCache.SetValue(Database, this.Scope, Key, Value);
|
||||
}
|
||||
private ValueType GetValue<ValueType>(string Key, ValueType Default)
|
||||
private T GetValue<T>(string Key, T Default)
|
||||
{
|
||||
return ConfigurationCache.GetConfigurationValue(Database, this.Scope, Key, Default);
|
||||
return ConfigurationCache.GetValue(Database, this.Scope, Key, Default);
|
||||
}
|
||||
|
||||
protected void Set<ValueType>(ValueType Value, [CallerMemberName] string Key = null)
|
||||
protected void Set<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
if (Key == null)
|
||||
throw new ArgumentNullException("Key");
|
||||
@@ -45,7 +49,7 @@ namespace Disco.Data.Configuration
|
||||
this.SetValue(Key, Value);
|
||||
}
|
||||
|
||||
protected ValueType Get<ValueType>(ValueType Default, [CallerMemberName] string Key = null)
|
||||
protected T Get<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
if (Key == null)
|
||||
throw new ArgumentNullException("Key");
|
||||
@@ -55,7 +59,7 @@ namespace Disco.Data.Configuration
|
||||
|
||||
protected void SetObsfucated(string Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
this.Set(ConfigurationCache.ObsfucateValue(Value), Key);
|
||||
this.Set(Value.Obsfucate(), Key);
|
||||
}
|
||||
|
||||
protected string GetDeobsfucated(string Default, [CallerMemberName] string Key = null)
|
||||
@@ -65,26 +69,40 @@ namespace Disco.Data.Configuration
|
||||
if (obsfucatedValue == null)
|
||||
return Default;
|
||||
else
|
||||
return ConfigurationCache.DeobsfucateValue(obsfucatedValue);
|
||||
return obsfucatedValue.Deobsfucate();
|
||||
}
|
||||
|
||||
protected void SetAsJson<ValueType>(ValueType Value, [CallerMemberName] string Key = null)
|
||||
protected void RemoveScope()
|
||||
{
|
||||
if (Value == null)
|
||||
this.Set<string>(null, Key);
|
||||
else
|
||||
this.Set(JsonConvert.SerializeObject(Value), Key);
|
||||
ConfigurationCache.RemoveScope(Database, this.Scope);
|
||||
}
|
||||
|
||||
protected ValueType GetFromJson<ValueType>(ValueType Default, [CallerMemberName] string Key = null)
|
||||
protected void RemoveItem(string Key)
|
||||
{
|
||||
var jsonValue = this.Get<string>(null, Key);
|
||||
|
||||
if (jsonValue == null)
|
||||
return Default;
|
||||
else
|
||||
return JsonConvert.DeserializeObject<ValueType>(jsonValue);
|
||||
ConfigurationCache.RemoveScopeKey(Database, this.Scope, Key);
|
||||
}
|
||||
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected void SetAsJson<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
this.Set(Value, Key);
|
||||
}
|
||||
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Get<T>(T Default) instead.")]
|
||||
protected T GetFromJson<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
return this.Get(Default, Key);
|
||||
}
|
||||
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected void SetAsEnum<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
this.Set(Value, Key);
|
||||
}
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected T GetFromEnum<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
return this.Get(Default, Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +1,384 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
using ConfigurationCacheItemType = Tuple<ConfigurationItem, object>;
|
||||
using ConfigurationCacheScopeType = ConcurrentDictionary<string, Tuple<ConfigurationItem, object>>;
|
||||
using ConfigurationCacheType = ConcurrentDictionary<string, ConcurrentDictionary<string, Tuple<ConfigurationItem, object>>>;
|
||||
|
||||
internal static class ConfigurationCache
|
||||
{
|
||||
#region Cache
|
||||
|
||||
private static Dictionary<String, Dictionary<String, ConfigurationItem>> configDictionary = new Dictionary<string, Dictionary<string, ConfigurationItem>>();
|
||||
private static List<ConfigurationItem> configurationItems = new List<ConfigurationItem>();
|
||||
private static object configurationItemsLock = new object();
|
||||
private static ConfigurationCacheType cacheStore = null;
|
||||
private static object configChangeLock = new object();
|
||||
|
||||
private static void LoadConfigurationItems(DiscoDataContext Database, string Scope, bool Reload)
|
||||
private static ConfigurationCacheType Cache(DiscoDataContext Database)
|
||||
{
|
||||
if (Reload || !configDictionary.ContainsKey(Scope))
|
||||
if (ConfigurationCache.cacheStore == null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
lock (configChangeLock)
|
||||
{
|
||||
if (Reload || !configDictionary.ContainsKey(Scope))
|
||||
if (ConfigurationCache.cacheStore == null)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cache-miss where Configuration Item requested from Cache-Only Configuration Context");
|
||||
throw new InvalidOperationException("The Configuration must be loaded at least once before a Cache-Only Configuration Context is used");
|
||||
|
||||
var newItems = Database.ConfigurationItems.Where(ci => ci.Scope == Scope).ToArray();
|
||||
var configurationItems = Database.ConfigurationItems.ToArray();
|
||||
|
||||
if (configDictionary.ContainsKey(Scope))
|
||||
{
|
||||
var existingItems = configDictionary[Scope];
|
||||
foreach (var existingItem in existingItems.Values)
|
||||
{
|
||||
configurationItems.Remove(existingItem);
|
||||
}
|
||||
}
|
||||
configurationItems.AddRange(newItems);
|
||||
configDictionary[Scope] = newItems.ToDictionary(ci => ci.Key);
|
||||
var indexedItems = configurationItems
|
||||
.GroupBy(ci => ci.Scope)
|
||||
.Select(g =>
|
||||
new KeyValuePair<string, ConfigurationCacheScopeType>(
|
||||
g.Key,
|
||||
new ConfigurationCacheScopeType(
|
||||
g.Select(i => new KeyValuePair<string, ConfigurationCacheItemType>(i.Key, Tuple.Create(i, (object)null))))));
|
||||
|
||||
cacheStore = new ConfigurationCacheType(indexedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigurationCache.cacheStore;
|
||||
}
|
||||
private static Dictionary<string, Dictionary<string, ConfigurationItem>> ConfigurationDictionary(DiscoDataContext Database, string IncludingScope)
|
||||
|
||||
private static ConfigurationCacheItemType CacheGetItem(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
LoadConfigurationItems(Database, IncludingScope, false);
|
||||
return configDictionary;
|
||||
}
|
||||
private static ConfigurationItem ConfigurationItem(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
Dictionary<string, ConfigurationItem> scopeDict = default(Dictionary<string, ConfigurationItem>);
|
||||
if (ConfigurationDictionary(Database, Scope).TryGetValue(Scope, out scopeDict))
|
||||
var cache = Cache(Database);
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
ConfigurationItem item = default(ConfigurationItem);
|
||||
if (scopeDict.TryGetValue(Key, out item))
|
||||
ConfigurationCacheItemType item = default(ConfigurationCacheItemType);
|
||||
if (scopeCache.TryGetValue(Key, out item))
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static List<ConfigurationItem> ConfigurationItems(DiscoDataContext Database, string IncludingScope)
|
||||
|
||||
private static ConfigurationCacheItemType CacheSetItem(DiscoDataContext Database, string Scope, string Key, string Value, object ObjectValue)
|
||||
{
|
||||
LoadConfigurationItems(Database, IncludingScope, false);
|
||||
return configurationItems;
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
var item = CacheGetItem(Database, Scope, Key);
|
||||
|
||||
if (item == null && Value == null)
|
||||
{
|
||||
// No Change - already null
|
||||
return null;
|
||||
}
|
||||
else if (item == null)
|
||||
{
|
||||
// New Configuration Item
|
||||
lock (configChangeLock)
|
||||
{
|
||||
// Check again for thread safety
|
||||
item = CacheGetItem(Database, Scope, Key);
|
||||
if (item == null)
|
||||
{
|
||||
// Create Configuration Item
|
||||
var configItem = new ConfigurationItem() { Scope = Scope, Key = Key, Value = Value };
|
||||
item = new ConfigurationCacheItemType(configItem, ObjectValue);
|
||||
|
||||
// Add Item to DB
|
||||
Database.ConfigurationItems.Add(configItem);
|
||||
|
||||
// Add Item to Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (!cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache = new ConfigurationCacheScopeType();
|
||||
cacheStore.TryAdd(Scope, scopeCache);
|
||||
}
|
||||
scopeCache.TryAdd(Key, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
// Existing Configuration Item
|
||||
lock (configChangeLock)
|
||||
{
|
||||
var configItem = item.Item1;
|
||||
|
||||
// Compare Values
|
||||
if (item.Item1.Value == Value)
|
||||
{
|
||||
// No Change - Update Cache Reference Only
|
||||
return SetItemTypeValue(item, ObjectValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entityInfo = Database.Entry(configItem);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).First();
|
||||
}
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
// Remove item from Database
|
||||
Database.ConfigurationItems.Remove(configItem);
|
||||
|
||||
// Remove item from Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update Database
|
||||
configItem.Value = Value;
|
||||
|
||||
// Update Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out item);
|
||||
item = new ConfigurationCacheItemType(configItem, ObjectValue);
|
||||
scopeCache.TryAdd(Key, item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static ConfigurationCacheItemType SetItemTypeValue(ConfigurationCacheItemType ExistingItem, object Value)
|
||||
{
|
||||
var cache = ConfigurationCache.cacheStore;
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(ExistingItem.Item1.Scope, out scopeCache))
|
||||
{
|
||||
ConfigurationCacheItemType newItem = new ConfigurationCacheItemType(ExistingItem.Item1, Value);
|
||||
scopeCache.TryUpdate(ExistingItem.Item1.Key, newItem, ExistingItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Helpers
|
||||
internal static ValueType GetConfigurationValue<ValueType>(DiscoDataContext Database, string Scope, string Key, ValueType Default)
|
||||
#region Helpers
|
||||
private static bool IsConvertableFromString(Type t)
|
||||
{
|
||||
var ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null)
|
||||
if (t == typeof(Boolean) ||
|
||||
t == typeof(Char) ||
|
||||
t == typeof(SByte) ||
|
||||
t == typeof(Byte) ||
|
||||
t == typeof(Int16) || t == typeof(UInt16) ||
|
||||
t == typeof(Int32) || t == typeof(UInt32) ||
|
||||
t == typeof(Int64) || t == typeof(UInt64) ||
|
||||
t == typeof(Single) ||
|
||||
t == typeof(Double) ||
|
||||
t == typeof(Decimal) ||
|
||||
t == typeof(DateTime) ||
|
||||
t == typeof(String))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Cache Getters/Setters
|
||||
internal static T GetValue<T>(DiscoDataContext Database, string Scope, string Key, T Default)
|
||||
{
|
||||
var item = CacheGetItem(Database, Scope, Key);
|
||||
|
||||
if (item == null)
|
||||
return Default;
|
||||
else
|
||||
return (ValueType)Convert.ChangeType(ci.Value, typeof(ValueType));
|
||||
}
|
||||
internal static void SetConfigurationValue<ValueType>(DiscoDataContext Database, string Scope, string Key, ValueType Value)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a CacheOnly Context");
|
||||
|
||||
var ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null && Value != null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
if (item.Item2 != null && item.Item2.GetType() == typeof(T))
|
||||
{
|
||||
ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null)
|
||||
{
|
||||
// Create Configuration Item
|
||||
ci = new ConfigurationItem() { Scope = Scope, Key = Key, Value = Value.ToString() };
|
||||
// Add Item to DB & Internal Collections
|
||||
Database.ConfigurationItems.Add(ci);
|
||||
ConfigurationItems(Database, Scope).Add(ci);
|
||||
ConfigurationDictionary(Database, Scope)[Scope].Add(Key, ci);
|
||||
ci = null;
|
||||
}
|
||||
// Return Cached Item
|
||||
return (T)item.Item2;
|
||||
}
|
||||
}
|
||||
if (ci != null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
else
|
||||
{
|
||||
var entityInfo = Database.Entry(ci);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Scope from DB
|
||||
LoadConfigurationItems(Database, Scope, true);
|
||||
ci = ConfigurationItem(Database, Scope, Key);
|
||||
}
|
||||
// Convert Serialized Item
|
||||
Type itemType = typeof(T);
|
||||
object itemValue;
|
||||
|
||||
if (Value == null)
|
||||
if (itemType == typeof(string))
|
||||
{
|
||||
Database.ConfigurationItems.Remove(ci);
|
||||
configurationItems.Remove(ci);
|
||||
configDictionary[Scope].Remove(Key);
|
||||
// string
|
||||
itemValue = item.Item1.Value;
|
||||
}
|
||||
else if (itemType == typeof(object))
|
||||
{
|
||||
// object
|
||||
itemValue = item.Item1.Value;
|
||||
}
|
||||
else if (IsConvertableFromString(itemType))
|
||||
{
|
||||
// IConvertable
|
||||
itemValue = Convert.ChangeType(item.Item1.Value, itemType);
|
||||
}
|
||||
else if (itemType.BaseType != null && itemType.BaseType == typeof(Enum))
|
||||
{
|
||||
// Enum
|
||||
itemValue = Enum.Parse(typeof(T), item.Item1.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.Value = Value.ToString();
|
||||
// JSON Deserialize
|
||||
itemValue = JsonConvert.DeserializeObject<T>(item.Item1.Value);
|
||||
}
|
||||
|
||||
// Set Item in Cache
|
||||
SetItemTypeValue(item, itemValue);
|
||||
|
||||
return (T)itemValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal static void SetValue<T>(DiscoDataContext Database, string Scope, string Key, T Value)
|
||||
{
|
||||
Type valueType = typeof(T);
|
||||
string stringValue;
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
stringValue = null;
|
||||
}
|
||||
else if (valueType == typeof(object))
|
||||
{
|
||||
throw new ArgumentException(string.Format("Cannot serialize the configuration item [{0}].[{1}] which defines a type of [System.Object]", Scope, Key), "Value");
|
||||
}
|
||||
else if (IsConvertableFromString(valueType))
|
||||
{
|
||||
// string or supports IConvertable
|
||||
stringValue = Value.ToString();
|
||||
}
|
||||
else if (valueType.BaseType != null && valueType.BaseType == typeof(Enum))
|
||||
{
|
||||
// Enum
|
||||
stringValue = Value.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// JSON Serialize
|
||||
stringValue = JsonConvert.SerializeObject(Value);
|
||||
}
|
||||
|
||||
CacheSetItem(Database, Scope, Key, stringValue, Value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Cache Helpers
|
||||
|
||||
internal static IEnumerable<string> GetScopeKeys(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
var cache = Cache(Database);
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
return scopeCache.Keys.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveScope(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
lock (configChangeLock)
|
||||
{
|
||||
// Remove item from Database
|
||||
var items = Database.ConfigurationItems.Where(i => i.Scope == Scope).ToList();
|
||||
items.ForEach(i => Database.ConfigurationItems.Remove(i));
|
||||
|
||||
// Remove item from Cache
|
||||
if (cacheStore != null)
|
||||
{
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
cacheStore.TryRemove(Scope, out scopeCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveScopeKey(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
lock (configChangeLock)
|
||||
{
|
||||
var cacheItem = CacheGetItem(Database, Scope, Key);
|
||||
ConfigurationItem configItem = null;
|
||||
|
||||
// Remove item from Database
|
||||
if (cacheItem != null)
|
||||
{
|
||||
configItem = cacheItem.Item1;
|
||||
|
||||
var entityInfo = Database.Entry(configItem);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
if (configItem == null)
|
||||
{
|
||||
// Load Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).FirstOrDefault();
|
||||
}
|
||||
if (configItem != null)
|
||||
{
|
||||
Database.ConfigurationItems.Remove(configItem);
|
||||
}
|
||||
|
||||
// Remove item from Cache
|
||||
if (cacheItem != null)
|
||||
{
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out cacheItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<ConfigurationItem> GetConfigurationItems(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
return ConfigurationDictionary(Database, Scope)[Scope].Values.ToList();
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static string ObsfucateValue(string Value)
|
||||
#region Obsfucation Helpers
|
||||
internal static string Obsfucate(this string Value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Value))
|
||||
return Value;
|
||||
else
|
||||
return Convert.ToBase64String(Encoding.Unicode.GetBytes(Value));
|
||||
}
|
||||
internal static string DeobsfucateValue(string ObsfucatedValue)
|
||||
internal static string Deobsfucate(this string ObsfucatedValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ObsfucatedValue))
|
||||
return ObsfucatedValue;
|
||||
@@ -145,6 +386,5 @@ namespace Disco.Data.Configuration
|
||||
return Encoding.Unicode.GetString(Convert.FromBase64String(ObsfucatedValue));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using Disco.Data.Repository;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
public class ActiveDirectoryConfiguration : ConfigurationBase
|
||||
{
|
||||
public ActiveDirectoryConfiguration(DiscoDataContext Database) : base(Database) { }
|
||||
|
||||
public override string Scope
|
||||
{
|
||||
get { return "ActiveDirectory"; }
|
||||
}
|
||||
|
||||
public Dictionary<string, List<string>> SearchContainers
|
||||
{
|
||||
get
|
||||
{
|
||||
return Get<Dictionary<string, List<string>>>(null);
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool? SearchAllForestServers
|
||||
{
|
||||
get { return Get<bool?>(null); }
|
||||
set { Set(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
||||
//
|
||||
//
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Models.Repository;
|
||||
|
||||
//namespace Disco.Data.Configuration.Modules
|
||||
//{
|
||||
// public class DeviceProfileConfiguration : ConfigurationBase
|
||||
// {
|
||||
// private DeviceProfilesConfiguration deviceProfilesConfig;
|
||||
// private DeviceProfile deviceProfile;
|
||||
|
||||
// public DeviceProfileConfiguration(ConfigurationContext Context, DeviceProfile DeviceProfile)
|
||||
// : base(Context)
|
||||
// {
|
||||
// this.deviceProfilesConfig = Context.DeviceProfiles;
|
||||
// this.deviceProfile = DeviceProfile;
|
||||
// }
|
||||
|
||||
// public override string Scope
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return string.Format("DeviceProfile:{0}", this.deviceProfile.Id);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public string ComputerNameTemplate
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue("ComputerNameTemplate", "DeviceProfile.ShortName + '-' + SerialNumber");
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("ComputerNameTemplate", value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public enum DeviceProfileDistributionTypes : int
|
||||
// {
|
||||
// OneToMany = 0,
|
||||
// OneToOne = 1
|
||||
// }
|
||||
// public DeviceProfileDistributionTypes DistributionType
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return (DeviceProfileDistributionTypes)this.GetValue("DistributionType", (int)DeviceProfileDistributionTypes.OneToMany);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("DistributionType", (int)value);
|
||||
// }
|
||||
// }
|
||||
// public string OrganisationalUnit
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue<string>("OrganisationalUnit", null);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("OrganisationalUnit", value);
|
||||
// }
|
||||
// }
|
||||
// public bool AllocateWirelessCertificate
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue("AllocateWirelessCertificate", false);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("AllocateWirelessCertificate", value);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Services.Devices.Exporting;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
public class DevicesConfiguration : ConfigurationBase
|
||||
{
|
||||
public DevicesConfiguration(DiscoDataContext Database) : base(Database) { }
|
||||
|
||||
public override string Scope { get { return "Devices"; } }
|
||||
|
||||
public DeviceExportOptions LastExportOptions
|
||||
{
|
||||
get { return this.Get<DeviceExportOptions>(DeviceExportOptions.DefaultOptions()); }
|
||||
set { this.Set(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Job;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
@@ -27,5 +25,32 @@ namespace Disco.Data.Configuration.Modules
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of minutes since the last recorded action is performed on a job before it is considered 'Stale'
|
||||
/// </summary>
|
||||
public int StaleJobMinutesThreshold
|
||||
{
|
||||
get { return Get<int>(60 * 24 * 2); } // Default to 48 Hours (2 days)
|
||||
set
|
||||
{
|
||||
if (value < 0)
|
||||
throw new ArgumentOutOfRangeException("value", "The Stale Job Minutes Threshold cannot be less than zero");
|
||||
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public LocationModes LocationMode
|
||||
{
|
||||
get { return Get<LocationModes>(LocationModes.Unrestricted); }
|
||||
set { Set(value); }
|
||||
}
|
||||
|
||||
public List<string> LocationList
|
||||
{
|
||||
get { return Get<List<string>>(new List<string>()); }
|
||||
set { Set(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
using System;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Config;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Config;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
public class OrganisationAddressesConfiguration : ConfigurationBase
|
||||
{
|
||||
private const string scope = "OrganisationAddresses";
|
||||
|
||||
public OrganisationAddressesConfiguration(DiscoDataContext Database) : base(Database) { }
|
||||
|
||||
public override string Scope { get { return "OrganisationAddresses"; } }
|
||||
public override string Scope { get { return scope; } }
|
||||
|
||||
public OrganisationAddress GetAddress(int Id)
|
||||
{
|
||||
var address = default(OrganisationAddress);
|
||||
var addressString = this.Get<string>(null, Id.ToString());
|
||||
if (addressString != null)
|
||||
{
|
||||
if (addressString.StartsWith("{"))
|
||||
{
|
||||
// Assume Json
|
||||
address = JsonConvert.DeserializeObject<OrganisationAddress>(addressString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume Old Storage Method
|
||||
address = OrganisationAddress.FromConfigurationEntry(Id, addressString);
|
||||
}
|
||||
}
|
||||
return address;
|
||||
return this.Get<OrganisationAddress>(null, Id.ToString());
|
||||
}
|
||||
public OrganisationAddress SetAddress(OrganisationAddress Address)
|
||||
{
|
||||
@@ -41,25 +25,21 @@ namespace Disco.Data.Configuration.Modules
|
||||
Address.Id = NextOrganisationAddressId;
|
||||
}
|
||||
|
||||
string addressString = JsonConvert.SerializeObject(Address);
|
||||
this.Set(Address, Address.Id.ToString());
|
||||
|
||||
this.Set(addressString, Address.Id.ToString()); //Address.ToConfigurationEntry());
|
||||
return Address;
|
||||
}
|
||||
public void RemoveAddress(int Id)
|
||||
{
|
||||
// Set Config Item to null = Remove Configuration Item
|
||||
this.Set<string>(null, Id.ToString());
|
||||
// Remove Configuration Item
|
||||
this.RemoveItem(Id.ToString());
|
||||
}
|
||||
|
||||
public List<OrganisationAddress> Addresses
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Items.Select(ca => ca.Value.StartsWith("{") ?
|
||||
JsonConvert.DeserializeObject<OrganisationAddress>(ca.Value) :
|
||||
OrganisationAddress.FromConfigurationEntry(int.Parse(ca.Key), ca.Value)
|
||||
).ToList();
|
||||
return this.ItemKeys.Select(key => this.Get<OrganisationAddress>(null, key)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,5 +58,19 @@ namespace Disco.Data.Configuration.Modules
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MigrateDatabase(DiscoDataContext Database)
|
||||
{
|
||||
// Migrate all organisation addresses to JSON
|
||||
if (Database.ConfigurationItems.Count(i => i.Scope == scope && !i.Value.StartsWith("{")) > 0)
|
||||
{
|
||||
var items = Database.ConfigurationItems.Where(i => i.Scope == scope && !i.Value.StartsWith("{")).ToList();
|
||||
items.ForEach(i =>
|
||||
{
|
||||
i.Value = JsonConvert.SerializeObject(OrganisationAddress.FromConfigurationEntry(int.Parse(i.Key), i.Value));
|
||||
});
|
||||
Database.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Interop.Community;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
@@ -21,6 +15,8 @@ namespace Disco.Data.Configuration
|
||||
this.moduleDeviceProfilesConfiguration = new Lazy<Modules.DeviceProfilesConfiguration>(() => new Modules.DeviceProfilesConfiguration(Database));
|
||||
this.moduleOrganisationAddressesConfiguration = new Lazy<Modules.OrganisationAddressesConfiguration>(() => new Modules.OrganisationAddressesConfiguration(Database));
|
||||
this.moduleJobPreferencesConfiguration = new Lazy<Modules.JobPreferencesConfiguration>(() => new Modules.JobPreferencesConfiguration(Database));
|
||||
this.moduleActiveDirectoryConfiguration = new Lazy<Modules.ActiveDirectoryConfiguration>(() => new Modules.ActiveDirectoryConfiguration(Database));
|
||||
this.moduleDevicesConfiguration = new Lazy<Modules.DevicesConfiguration>(() => new Modules.DevicesConfiguration(Database));
|
||||
}
|
||||
|
||||
#region Configuration Modules
|
||||
@@ -29,6 +25,8 @@ namespace Disco.Data.Configuration
|
||||
private Lazy<Modules.DeviceProfilesConfiguration> moduleDeviceProfilesConfiguration;
|
||||
private Lazy<Modules.OrganisationAddressesConfiguration> moduleOrganisationAddressesConfiguration;
|
||||
private Lazy<Modules.JobPreferencesConfiguration> moduleJobPreferencesConfiguration;
|
||||
private Lazy<Modules.ActiveDirectoryConfiguration> moduleActiveDirectoryConfiguration;
|
||||
private Lazy<Modules.DevicesConfiguration> moduleDevicesConfiguration;
|
||||
|
||||
public Modules.BootstrapperConfiguration Bootstrapper
|
||||
{
|
||||
@@ -58,6 +56,20 @@ namespace Disco.Data.Configuration
|
||||
return moduleJobPreferencesConfiguration.Value;
|
||||
}
|
||||
}
|
||||
public Modules.ActiveDirectoryConfiguration ActiveDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
return moduleActiveDirectoryConfiguration.Value;
|
||||
}
|
||||
}
|
||||
public Modules.DevicesConfiguration Devices
|
||||
{
|
||||
get
|
||||
{
|
||||
return moduleDevicesConfiguration.Value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -94,6 +106,18 @@ namespace Disco.Data.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
public string Administrators
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Get<string>("Domain Admins,Disco Admins");
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
#region Plugin Locations
|
||||
public string PluginsLocation
|
||||
{
|
||||
@@ -249,11 +273,11 @@ namespace Disco.Data.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.GetFromJson<UpdateResponse>(null);
|
||||
return this.Get<UpdateResponse>(null);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SetAsJson(value);
|
||||
this.Set(value);
|
||||
}
|
||||
}
|
||||
public bool UpdateBetaDeployment
|
||||
|
||||
@@ -40,26 +40,30 @@
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\EntityFramework.5.0.0\lib\net45\EntityFramework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\packages\Newtonsoft.Json.6.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.Entity" />
|
||||
<Reference Include="System.DirectoryServices" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Reactive.Core">
|
||||
<HintPath>..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll</HintPath>
|
||||
<Reference Include="System.Reactive.Core, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Core.2.2.4\lib\net45\System.Reactive.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.Interfaces">
|
||||
<HintPath>..\packages\Rx-Interfaces.2.1.30214.0\lib\Net45\System.Reactive.Interfaces.dll</HintPath>
|
||||
<Reference Include="System.Reactive.Interfaces, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Interfaces.2.2.4\lib\net45\System.Reactive.Interfaces.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.Linq">
|
||||
<HintPath>..\packages\Rx-Linq.2.1.30214.0\lib\Net45\System.Reactive.Linq.dll</HintPath>
|
||||
<Reference Include="System.Reactive.Linq, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-Linq.2.2.4\lib\net45\System.Reactive.Linq.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Reactive.PlatformServices">
|
||||
<HintPath>..\packages\Rx-PlatformServices.2.1.30214.0\lib\Net45\System.Reactive.PlatformServices.dll</HintPath>
|
||||
<Reference Include="System.Reactive.PlatformServices, Version=2.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Rx-PlatformServices.2.2.4\lib\net45\System.Reactive.PlatformServices.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Web" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
@@ -72,10 +76,11 @@
|
||||
<Compile Include="Configuration\CommunityHelpers.cs" />
|
||||
<Compile Include="Configuration\ConfigurationBase.cs" />
|
||||
<Compile Include="Configuration\ConfigurationCache.cs" />
|
||||
<Compile Include="Configuration\Modules\ActiveDirectoryConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\DevicesConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\JobPreferencesConfiguration.cs" />
|
||||
<Compile Include="Configuration\SystemConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\BootstrapperConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\DeviceProfileConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\DeviceProfilesConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\OrganisationAddressesConfiguration.cs" />
|
||||
<Compile Include="Migrations\201204250418485_DBv0.cs" />
|
||||
@@ -126,6 +131,18 @@
|
||||
<Compile Include="Migrations\201310282325491_DBv11.Designer.cs">
|
||||
<DependentUpon>201310282325491_DBv11.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201402032322432_DBv12.cs" />
|
||||
<Compile Include="Migrations\201402032322432_DBv12.Designer.cs">
|
||||
<DependentUpon>201402032322432_DBv12.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201404080227546_DBv13.cs" />
|
||||
<Compile Include="Migrations\201404080227546_DBv13.Designer.cs">
|
||||
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201406160912525_DBv14.cs" />
|
||||
<Compile Include="Migrations\201406160912525_DBv14.Designer.cs">
|
||||
<DependentUpon>201406160912525_DBv14.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\Configuration.cs" />
|
||||
<Compile Include="Migrations\DiscoDataMigrator.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
@@ -174,6 +191,15 @@
|
||||
<EmbeddedResource Include="Migrations\201310282325491_DBv11.resx">
|
||||
<DependentUpon>201310282325491_DBv11.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201402032322432_DBv12.resx">
|
||||
<DependentUpon>201402032322432_DBv12.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201404080227546_DBv13.resx">
|
||||
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201406160912525_DBv14.resx">
|
||||
<DependentUpon>201406160912525_DBv14.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
@@ -187,7 +213,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" 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_StartDate="2014/6/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
// <auto-generated />
|
||||
namespace Disco.Data.Migrations
|
||||
{
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
public sealed partial class DBv12 : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(DBv12));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201402032322432_DBv12"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace Disco.Data.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class DBv12 : DbMigration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
CreateTable(
|
||||
"dbo.JobQueueJobs",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
JobQueueId = c.Int(nullable: false),
|
||||
JobId = c.Int(nullable: false),
|
||||
AddedDate = c.DateTime(nullable: false),
|
||||
AddedUserId = c.String(nullable: false, maxLength: 50),
|
||||
AddedComment = c.String(),
|
||||
RemovedDate = c.DateTime(),
|
||||
RemovedUserId = c.String(maxLength: 50),
|
||||
RemovedComment = c.String(),
|
||||
SLAExpiresDate = c.DateTime(),
|
||||
Priority = c.Byte(nullable: false),
|
||||
})
|
||||
.PrimaryKey(t => t.Id)
|
||||
.ForeignKey("dbo.JobQueues", t => t.JobQueueId)
|
||||
.ForeignKey("dbo.Jobs", t => t.JobId)
|
||||
.ForeignKey("dbo.Users", t => t.AddedUserId)
|
||||
.ForeignKey("dbo.Users", t => t.RemovedUserId)
|
||||
.Index(t => t.JobQueueId)
|
||||
.Index(t => t.JobId)
|
||||
.Index(t => t.AddedUserId)
|
||||
.Index(t => t.RemovedUserId);
|
||||
|
||||
CreateTable(
|
||||
"dbo.JobQueues",
|
||||
c => new
|
||||
{
|
||||
Id = c.Int(nullable: false, identity: true),
|
||||
Name = c.String(nullable: false, maxLength: 100),
|
||||
Description = c.String(maxLength: 500),
|
||||
Icon = c.String(nullable: false, maxLength: 25),
|
||||
IconColour = c.String(nullable: false, maxLength: 10),
|
||||
DefaultSLAExpiry = c.Int(),
|
||||
Priority = c.Byte(nullable: false),
|
||||
SubjectIds = c.String(),
|
||||
})
|
||||
.PrimaryKey(t => t.Id);
|
||||
|
||||
CreateTable(
|
||||
"dbo.JobQueues_JobSubTypes",
|
||||
c => new
|
||||
{
|
||||
JobQueue_Id = c.Int(nullable: false),
|
||||
JobSubType_Id = c.String(nullable: false, maxLength: 20),
|
||||
JobSubType_JobTypeId = c.String(nullable: false, maxLength: 5),
|
||||
})
|
||||
.PrimaryKey(t => new { t.JobQueue_Id, t.JobSubType_Id, t.JobSubType_JobTypeId })
|
||||
.ForeignKey("dbo.JobQueues", t => t.JobQueue_Id, cascadeDelete: true)
|
||||
.ForeignKey("dbo.JobSubTypes", t => new { t.JobSubType_Id, t.JobSubType_JobTypeId }, cascadeDelete: true)
|
||||
.Index(t => t.JobQueue_Id)
|
||||
.Index(t => new { t.JobSubType_Id, t.JobSubType_JobTypeId });
|
||||
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
DropIndex("dbo.JobQueues_JobSubTypes", new[] { "JobSubType_Id", "JobSubType_JobTypeId" });
|
||||
DropIndex("dbo.JobQueues_JobSubTypes", new[] { "JobQueue_Id" });
|
||||
DropIndex("dbo.JobQueueJobs", new[] { "RemovedUserId" });
|
||||
DropIndex("dbo.JobQueueJobs", new[] { "AddedUserId" });
|
||||
DropIndex("dbo.JobQueueJobs", new[] { "JobId" });
|
||||
DropIndex("dbo.JobQueueJobs", new[] { "JobQueueId" });
|
||||
DropForeignKey("dbo.JobQueues_JobSubTypes", new[] { "JobSubType_Id", "JobSubType_JobTypeId" }, "dbo.JobSubTypes");
|
||||
DropForeignKey("dbo.JobQueues_JobSubTypes", "JobQueue_Id", "dbo.JobQueues");
|
||||
DropForeignKey("dbo.JobQueueJobs", "RemovedUserId", "dbo.Users");
|
||||
DropForeignKey("dbo.JobQueueJobs", "AddedUserId", "dbo.Users");
|
||||
DropForeignKey("dbo.JobQueueJobs", "JobId", "dbo.Jobs");
|
||||
DropForeignKey("dbo.JobQueueJobs", "JobQueueId", "dbo.JobQueues");
|
||||
DropTable("dbo.JobQueues_JobSubTypes");
|
||||
DropTable("dbo.JobQueues");
|
||||
DropTable("dbo.JobQueueJobs");
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,27 @@
|
||||
// <auto-generated />
|
||||
namespace Disco.Data.Migrations
|
||||
{
|
||||
using System.Data.Entity.Migrations;
|
||||
using System.Data.Entity.Migrations.Infrastructure;
|
||||
using System.Resources;
|
||||
|
||||
public sealed partial class DBv13 : IMigrationMetadata
|
||||
{
|
||||
private readonly ResourceManager Resources = new ResourceManager(typeof(DBv13));
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201404080227546_DBv13"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Target
|
||||
{
|
||||
get { return Resources.GetString("Target"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Disco.Data.Migrations
|
||||
{
|
||||
using System;
|
||||
using System.Data.Entity.Migrations;
|
||||
|
||||
public partial class DBv13 : DbMigration
|
||||
{
|
||||
public override void Up()
|
||||
{
|
||||
AlterColumn("dbo.Devices", "ComputerName", c => c.String(maxLength: 50));
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
{
|
||||
AlterColumn("dbo.Devices", "ComputerName", c => c.String(maxLength: 24));
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user