From db73cc1a129af1f147c86be5fec214c662eca020 Mon Sep 17 00:00:00 2001 From: Gary Sharp Date: Thu, 10 Apr 2014 17:58:04 +1000 Subject: [PATCH] Feature #42: Active Directory Interop Upgrade AD Interop moved to Disco.Services; Supports multi-domain environments, sites, and searching restricted with OUs. --- Disco.BI/BI/DeviceBI/Enrol.cs | 159 ++- .../BI/Expressions/Extensions/DeviceExt.cs | 9 +- Disco.BI/BI/Expressions/Extensions/UserExt.cs | 9 +- .../BI/Extensions/ClientServicesExtensions.cs | 2 +- .../BI/Extensions/DeviceActionExtensions.cs | 20 +- Disco.BI/BI/Extensions/DeviceExtensions.cs | 26 +- .../Extensions/DocumentTemplateExtensions.cs | 2 +- Disco.BI/BI/Extensions/JobActionExtensions.cs | 24 +- Disco.BI/BI/Extensions/JobExtensions.cs | 6 +- .../BI/Extensions/JobQueueActionExtensions.cs | 4 +- Disco.BI/BI/Extensions/UserExtensions.cs | 6 +- .../ActiveDirectory/ActiveDirectory.cs | 1026 ++++++++--------- .../ActiveDirectoryGroupExtensions.cs | 19 - .../ActiveDirectory/ActiveDirectoryHelpers.cs | 364 +++--- ...ActiveDirectoryMachineAccountExtensions.cs | 301 ----- .../ActiveDirectoryOrganisationalUnit.cs | 26 +- ...eDirectoryUpdateLastNetworkLogonDateJob.cs | 488 ++++---- .../ActiveDirectoryUserAccountExtensions.cs | 74 +- Disco.BI/BI/Interop/Pdf/PdfGenerator.cs | 10 +- .../HeldDeviceNotifications.cs | 2 +- .../UserHeldDeviceNotifications.cs | 2 +- Disco.BI/BI/JobBI/Utilities.cs | 8 +- Disco.BI/Disco.BI.csproj | 3 - Disco.Client/Extensions/EnrolExtensions.cs | 1 + Disco.Client/Interop/SystemAudit.cs | 5 +- .../Modules/ActiveDirectoryConfiguration.cs | 37 + .../Configuration/SystemConfiguration.cs | 9 + Disco.Data/Disco.Data.csproj | 9 + .../201404080227546_DBv13.Designer.cs | 27 + .../Migrations/201404080227546_DBv13.cs | 18 + .../Migrations/201404080227546_DBv13.resx | 123 ++ Disco.Data/Repository/DiscoDataSeeder.cs | 129 +++ Disco.Models/ClientServices/Enrol.cs | 1 + Disco.Models/Disco.Models.csproj | 6 +- .../ActiveDirectory/ActiveDirectoryDomain.cs | 30 + .../ActiveDirectory/ActiveDirectoryGroup.cs | 15 +- .../ActiveDirectoryMachineAccount.cs | 25 +- .../ActiveDirectoryOrganisationalUnit.cs | 16 + .../ActiveDirectorySearchResult.cs | 16 + .../ActiveDirectoryUserAccount.cs | 23 +- .../ActiveDirectory/IActiveDirectoryObject.cs | 11 +- Disco.Models/Repository/Device/Device.cs | 24 +- Disco.Models/Repository/User/User.cs | 28 +- .../Jobs/JobLists/JobTableItemModel.cs | 5 +- .../Searching/DeviceSearchResultItem.cs | 2 +- .../Services/Searching/JobSearchResultItem.cs | 3 +- .../Searching/UserSearchResultItem.cs | 2 +- Disco.Services/Authorization/Claims.cs | 8 + .../DiscoAuthorizeBaseAttribute.cs | 2 +- .../Configuration/System/SystemClaims.cs | 3 + .../Authorization/Roles/RoleCache.cs | 2 +- Disco.Services/Disco.Services.csproj | 8 +- .../ActiveDirectory/ActiveDirectory.cs | 531 +++++++++ .../ActiveDirectoryExtensions.cs | 391 +++++++ .../Internal/ADDiscoverForestServers.cs | 68 ++ .../ActiveDirectory/Internal/ADGroupCache.cs | 23 +- .../ActiveDirectory/Internal/ADInterop.cs | 617 ++++++++++ .../ADUpdateLastNetworkLogonDateJob.cs | 231 ++++ Disco.Services/Jobs/JobExtensions.cs | 4 + .../Jobs/JobLists/JobTableExtensions.cs | 5 + .../Jobs/JobQueues/JobQueueService.cs | 6 +- .../Plugins/PluginWebHandlerController.cs | 2 +- Disco.Services/Searching/Search.cs | 25 +- Disco.Services/Tasks/ScheduledTaskStatus.cs | 21 +- Disco.Services/Users/Searching.cs | 13 - Disco.Services/Users/UserExtensions.cs | 42 + Disco.Services/Users/UserService.cs | 39 +- Disco.Web/App_Code/AjaxHelpers.generated.cs | 2 +- Disco.Web/App_Code/CommonHelpers.cshtml | 6 +- Disco.Web/App_Code/CommonHelpers.generated.cs | 18 +- Disco.Web/App_Start/AppConfig.cs | 16 +- .../AuthorizationRoleController.cs | 20 +- .../Areas/API/Controllers/DeviceController.cs | 8 +- .../Controllers/DeviceProfileController.cs | 20 +- .../Areas/API/Controllers/JobController.cs | 26 +- .../API/Controllers/JobQueueController.cs | 12 +- .../Areas/API/Controllers/SystemController.cs | 99 +- .../Areas/API/Controllers/UserController.cs | 31 +- .../System/DomainOrganisationalUnitsModel.cs | 47 + .../AuthorizationRoleController.cs | 3 +- .../Controllers/DeviceProfileController.cs | 4 +- .../Config/Controllers/JobQueueController.cs | 3 +- .../Controllers/SystemConfigController.cs | 15 - .../Models/AuthorizationRole/ShowModel.cs | 2 +- .../Config/Models/SystemConfig/IndexModel.cs | 63 +- .../AuthorizationRole/Create.generated.cs | 3 +- .../AuthorizationRole/Index.generated.cs | 3 +- .../Views/AuthorizationRole/Show.generated.cs | 3 +- .../Config/Views/Config/Index.generated.cs | 3 +- .../Views/DeviceBatch/Create.generated.cs | 3 +- .../Views/DeviceBatch/Index.generated.cs | 3 +- .../Views/DeviceBatch/Show.generated.cs | 3 +- .../Views/DeviceBatch/Timeline.generated.cs | 3 +- .../GenericComponents.generated.cs | 3 +- .../Views/DeviceModel/Index.generated.cs | 3 +- .../Views/DeviceModel/Show.generated.cs | 3 +- .../_DeviceComponentsTable.generated.cs | 3 +- .../Config/Views/DeviceProfile/Create.cshtml | 1 + .../Views/DeviceProfile/Create.generated.cs | 16 +- .../Views/DeviceProfile/Defaults.generated.cs | 3 +- .../Views/DeviceProfile/Index.generated.cs | 3 +- .../Config/Views/DeviceProfile/Show.cshtml | 223 ++-- .../Views/DeviceProfile/Show.generated.cs | 423 ++++--- .../Views/DeviceProfile/_Table.generated.cs | 3 +- .../DeviceProfile/_TableRender.generated.cs | 3 +- .../DocumentTemplate/Create.generated.cs | 3 +- .../ExpressionBrowser2.generated.cs | 3 +- .../ImportStatus.generated.cs | 3 +- .../Views/DocumentTemplate/Index.generated.cs | 3 +- .../Views/DocumentTemplate/Show.generated.cs | 2 +- .../UndetectedPages.generated.cs | 3 +- .../_ExpressionsTable.generated.cs | 3 +- .../Config/Views/Enrolment/Index.generated.cs | 3 +- .../Views/Enrolment/Status.generated.cs | 3 +- .../Views/Expressions/Editor.generated.cs | 3 +- .../Config/Views/JobQueue/Create.generated.cs | 3 +- .../Config/Views/JobQueue/Index.generated.cs | 3 +- .../Config/Views/Logging/Index.generated.cs | 3 +- .../Views/Logging/TaskStatus.generated.cs | 3 +- .../Views/Organisation/Index.generated.cs | 3 +- .../Config/Views/Plugins/Index.generated.cs | 3 +- .../Config/Views/Plugins/Install.generated.cs | 3 +- .../ProviderConfiguration.generated.cs | 3 +- .../Views/Shared/LogEvents.generated.cs | 3 +- .../Config/Views/SystemConfig/Index.cshtml | 297 ++++- .../Views/SystemConfig/Index.generated.cs | 945 ++++++++++++++- Disco.Web/Areas/Config/Views/Web.config | 5 + .../Config/Views/_ViewStart.generated.cs | 3 +- .../Controllers/HeldDevicesController.cs | 2 +- .../Views/HeldDevices/Index.generated.cs | 3 +- .../HeldDevices/Noticeboard.generated.cs | 3 +- .../Public/Views/Public/Credits.generated.cs | 3 +- .../Public/Views/Public/Index.generated.cs | 3 +- .../Public/Views/Public/Licence.generated.cs | 3 +- .../Views/UserHeldDevices/Index.generated.cs | 3 +- .../UserHeldDevices/Noticeboard.generated.cs | 3 +- .../Public/Views/_ViewStart.generated.cs | 3 +- Disco.Web/ClientSource/Style/Config.css | 30 + Disco.Web/ClientSource/Style/Config.less | 39 + Disco.Web/ClientSource/Style/Config.min.css | 2 +- Disco.Web/Controllers/SearchController.cs | 2 +- Disco.Web/Controllers/UserController.cs | 13 +- Disco.Web/Disco.Web.csproj | 2 + Disco.Web/Extensions/T4MVCExtensions.cs | 78 ++ Disco.Web/T4MVC.cs | 162 ++- .../Views/Device/AddOffline.generated.cs | 3 +- .../_AssignmentHistory.generated.cs | 3 +- .../DeviceParts/_Certificates.generated.cs | 3 +- .../Device/DeviceParts/_Details.generated.cs | 2 +- .../Device/DeviceParts/_Jobs.generated.cs | 2 +- .../Device/DeviceParts/_Resources.cshtml | 4 +- .../DeviceParts/_Resources.generated.cs | 12 +- .../Views/Device/DeviceParts/_Subject.cshtml | 19 +- .../Device/DeviceParts/_Subject.generated.cs | 529 +++++---- .../Views/Device/ImportExport.generated.cs | 3 +- .../Views/Device/ImportReview.generated.cs | 3 +- Disco.Web/Views/Device/Index.generated.cs | 3 +- Disco.Web/Views/Device/Show.generated.cs | 3 +- .../Views/Device/_DeviceTable.generated.cs | 2 +- .../Views/Device/_ViewStart.generated.cs | 3 +- .../Views/InitialConfig/Complete.generated.cs | 3 +- .../Views/InitialConfig/Database.generated.cs | 3 +- .../InitialConfig/FileStore.generated.cs | 3 +- .../InitialConfig/RestartWebApp.generated.cs | 3 +- .../Views/InitialConfig/Welcome.generated.cs | 3 +- .../Views/InitialConfig/_Layout.generated.cs | 3 +- .../InitialConfig/_ViewStart.generated.cs | 3 +- .../Job/JobParts/Components.generated.cs | 3 +- .../Views/Job/JobParts/Flags.generated.cs | 2 +- .../Views/Job/JobParts/Insurance.generated.cs | 2 +- .../JobParts/JobMetaAdditions1.generated.cs | 3 +- .../Job/JobParts/NonWarranty.generated.cs | 2 +- .../JobParts/NonWarrantyFinance.generated.cs | 2 +- .../Views/Job/JobParts/Queues.generated.cs | 2 +- .../Views/Job/JobParts/Repairs.generated.cs | 2 +- Disco.Web/Views/Job/JobParts/Resources.cshtml | 8 +- .../Views/Job/JobParts/Resources.generated.cs | 54 +- Disco.Web/Views/Job/JobParts/_Subject.cshtml | 2 +- .../Views/Job/JobParts/_Subject.generated.cs | 56 +- Disco.Web/Views/Job/List.generated.cs | 2 +- Disco.Web/Views/Job/LogWarranty.generated.cs | 3 +- .../Job/LogWarrantyDisclose.generated.cs | 3 +- .../Views/Job/LogWarrantyError.generated.cs | 3 +- Disco.Web/Views/Job/Show.generated.cs | 2 +- .../WarrantyProviderJobDetails.generated.cs | 3 +- Disco.Web/Views/Job/_CreateSubject.cshtml | 2 +- .../Views/Job/_CreateSubject.generated.cs | 7 +- Disco.Web/Views/Job/_ViewStart.generated.cs | 3 +- Disco.Web/Views/Search/Query.generated.cs | 3 +- .../AccessDeniedException.generated.cs | 7 +- .../DisplayTemplates/Exception.generated.cs | 7 +- Disco.Web/Views/Shared/Error.generated.cs | 3 +- .../Views/Shared/_DialogLayout.generated.cs | 2 +- .../Views/Shared/_EmptyLayout.generated.cs | 3 +- Disco.Web/Views/Shared/_JobTable.generated.cs | 2 +- Disco.Web/Views/Shared/_JobTableRender.cshtml | 6 +- .../Views/Shared/_JobTableRender.generated.cs | 20 +- Disco.Web/Views/Shared/_Layout.cshtml | 2 +- Disco.Web/Views/Shared/_Layout.generated.cs | 6 +- .../Views/Shared/_PublicLayout.generated.cs | 3 +- .../Views/Shared/_SearchDialog.generated.cs | 3 +- Disco.Web/Views/Update/Index.generated.cs | 3 +- Disco.Web/Views/User/Index.generated.cs | 3 +- Disco.Web/Views/User/Show.cshtml | 2 +- Disco.Web/Views/User/Show.generated.cs | 5 +- .../UserParts/_AssignmentHistory.generated.cs | 3 +- .../User/UserParts/_Authorization.cshtml | 2 +- .../UserParts/_Authorization.generated.cs | 5 +- .../Views/User/UserParts/_Jobs.generated.cs | 3 +- .../Views/User/UserParts/_Resources.cshtml | 6 +- .../User/UserParts/_Resources.generated.cs | 14 +- .../Views/User/UserParts/_Subject.cshtml | 8 +- .../User/UserParts/_Subject.generated.cs | 40 +- Disco.Web/Views/User/_UserTable.generated.cs | 2 +- Disco.Web/Views/User/_ViewStart.generated.cs | 3 +- Disco.Web/Views/_ViewStart.generated.cs | 3 +- Disco.Web/Web.Release.config | 4 +- Disco.Web/Web.config | 2 +- 218 files changed, 6383 insertions(+), 2535 deletions(-) delete mode 100644 Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryGroupExtensions.cs delete mode 100644 Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryMachineAccountExtensions.cs create mode 100644 Disco.Data/Configuration/Modules/ActiveDirectoryConfiguration.cs create mode 100644 Disco.Data/Migrations/201404080227546_DBv13.Designer.cs create mode 100644 Disco.Data/Migrations/201404080227546_DBv13.cs create mode 100644 Disco.Data/Migrations/201404080227546_DBv13.resx create mode 100644 Disco.Models/Interop/ActiveDirectory/ActiveDirectoryDomain.cs create mode 100644 Disco.Models/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs create mode 100644 Disco.Models/Interop/ActiveDirectory/ActiveDirectorySearchResult.cs create mode 100644 Disco.Services/Interop/ActiveDirectory/ActiveDirectory.cs create mode 100644 Disco.Services/Interop/ActiveDirectory/ActiveDirectoryExtensions.cs create mode 100644 Disco.Services/Interop/ActiveDirectory/Internal/ADDiscoverForestServers.cs rename Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryCachedGroups.cs => Disco.Services/Interop/ActiveDirectory/Internal/ADGroupCache.cs (95%) create mode 100644 Disco.Services/Interop/ActiveDirectory/Internal/ADInterop.cs create mode 100644 Disco.Services/Interop/ActiveDirectory/Internal/ADUpdateLastNetworkLogonDateJob.cs delete mode 100644 Disco.Services/Users/Searching.cs create mode 100644 Disco.Services/Users/UserExtensions.cs create mode 100644 Disco.Web/Areas/API/Models/System/DomainOrganisationalUnitsModel.cs create mode 100644 Disco.Web/Extensions/T4MVCExtensions.cs diff --git a/Disco.BI/BI/DeviceBI/Enrol.cs b/Disco.BI/BI/DeviceBI/Enrol.cs index 1e0ba29a..de26378d 100644 --- a/Disco.BI/BI/DeviceBI/Enrol.cs +++ b/Disco.BI/BI/DeviceBI/Enrol.cs @@ -1,13 +1,14 @@ 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 +243,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 +253,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 +268,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 +281,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 +295,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); + ActiveDirectoryUserAccount AssignedUserInfo = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId); EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier); response.DeviceAssignedUserUsername = AssignedUserInfo.SamAccountName; response.DeviceAssignedUserDomain = AssignedUserInfo.Domain; response.DeviceAssignedUserName = AssignedUserInfo.DisplayName; response.DeviceAssignedUserSID = AssignedUserInfo.SecurityIdentifier; } - response.DeviceComputerName = RepoDevice.ComputerName; + response.DeviceComputerName = RepoDevice.DeviceDomainId; EnrolmentLog.LogSessionProgress(sessionId, 100, "Completed Successfully"); } catch (EnrolSafeException ex) @@ -323,14 +324,26 @@ namespace Disco.BI.DeviceBI } public static EnrolResponse Enrol(DiscoDataContext Database, string Username, Models.ClientServices.Enrol Request) { - ActiveDirectoryMachineAccount MachineInfo = null; + ActiveDirectoryMachineAccount adMachineAccount = null; + EnrolResponse response = new EnrolResponse(); + AuthorizationToken authenticatedToken = null; bool isAuthenticated = false; + + ActiveDirectoryDomain domain = null; + Lazy domainController = new Lazy(() => { + if (domain == null) + throw new InvalidOperationException("The [domain] variable must be initialized first"); + return domain.RetrieveWritableDomainController(); + }); + 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,9 @@ 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 (!authenticatedToken.User.UserId.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.UserId)); } } else @@ -380,10 +393,16 @@ namespace Disco.BI.DeviceBI System.Guid? uuidGuid = null; System.Guid? macAddressGuid = null; if (!string.IsNullOrEmpty(Request.DeviceUUID)) - uuidGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(Request.DeviceUUID); + uuidGuid = ActiveDirectoryExtensions.NetbootGUIDFromUUID(Request.DeviceUUID); if (!string.IsNullOrEmpty(Request.DeviceLanMacAddress)) - macAddressGuid = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress); - MachineInfo = ActiveDirectory.GetMachineAccount(Request.DeviceComputerName, uuidGuid, macAddressGuid); + macAddressGuid = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(Request.DeviceLanMacAddress); + + if (domain == null) + domain = ActiveDirectory.GetDomainByDnsName(Request.DeviceDNSDomainName); + + var requestDeviceId = string.Format(@"{0}\{1}", domain.NetBiosName, Request.DeviceComputerName); + + adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, requestDeviceId, uuidGuid, macAddressGuid); } if (RepoDevice == null) { @@ -392,7 +411,7 @@ 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); @@ -402,7 +421,7 @@ namespace Disco.BI.DeviceBI RepoDevice = new Device { SerialNumber = Request.DeviceSerialNumber, - ComputerName = Request.DeviceComputerName, + DeviceDomainId = Request.DeviceComputerName, DeviceProfile = deviceProfile, DeviceModel = deviceModel, AllowUnauthenticatedEnrol = false, @@ -423,7 +442,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 +461,120 @@ 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.GetDomainByDistinguishedName(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 = ActiveDirectory.RetrieveMachineAccount(domainController.Value, RepoDevice.DeviceDomainId); + + response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, 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; } else { - response.DeviceComputerName = RepoDevice.ComputerName; - response.DeviceDomainName = RepoDevice.ComputerName; + var computerId = Disco.Services.UserExtensions.SplitUserId(RepoDevice.DeviceDomainId); + response.DeviceDomainName = computerId.Item1; + response.DeviceComputerName = computerId.Item2; } } 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.Name; + response.DeviceComputerName = adMachineAccount.Name; + response.DeviceDomainName = adMachineAccount.Domain; // 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.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit); + + var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain); + var computerNameSplit = Disco.Services.UserExtensions.SplitUserId(calculatedComputerName); + + if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.InvariantCultureIgnoreCase)) { 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 = computerNameSplit.Item1; + response.DeviceComputerName = computerNameSplit.Item2; // Create New Account - response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(ref MachineInfo, RepoDevice.ComputerName, RepoDevice.DeviceProfile.OrganisationalUnit, sessionId); + string offlineProvisionDiagnosicInfo; + + response.OfflineDomainJoin = ActiveDirectory.OfflineDomainJoinProvision(domain, domainController.Value, 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.InvariantCultureIgnoreCase)) // Custom OU { - string newOU = RepoDevice.DeviceProfile.OrganisationalUnit ?? "CN=Computers"; + var proposedDomain = ActiveDirectory.GetDomainByDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit); + var currentDomain = ActiveDirectory.GetDomainByDistinguishedName(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); + adMachineAccount = ActiveDirectory.RetrieveMachineAccount(domainController.Value, adMachineAccount.NetBiosId); 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,7 +585,7 @@ namespace Disco.BI.DeviceBI else { EnrolmentLog.LogSessionProgress(sessionId, 80, "Retrieving Active Directory Assigned User Account"); - ActiveDirectoryUserAccount AssignedUserInfo = ActiveDirectory.GetUserAccount(RepoDevice.AssignedUser.Id); + ActiveDirectoryUserAccount AssignedUserInfo = Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(RepoDevice.AssignedUser.UserId); EnrolmentLog.LogSessionTaskAssigningUser(sessionId, RepoDevice.SerialNumber, AssignedUserInfo.DisplayName, AssignedUserInfo.SamAccountName, AssignedUserInfo.Domain, AssignedUserInfo.SecurityIdentifier); response.AllowBootstrapperUninstall = true; response.DeviceAssignedUserIsLocalAdmin = RepoDevice.DeviceProfile.AssignedUserLocalAdmin; diff --git a/Disco.BI/BI/Expressions/Extensions/DeviceExt.cs b/Disco.BI/BI/Expressions/Extensions/DeviceExt.cs index d7476e9b..c147f49e 100644 --- a/Disco.BI/BI/Expressions/Extensions/DeviceExt.cs +++ b/Disco.BI/BI/Expressions/Extensions/DeviceExt.cs @@ -1,10 +1,7 @@ -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; namespace Disco.BI.Expressions.Extensions { diff --git a/Disco.BI/BI/Expressions/Extensions/UserExt.cs b/Disco.BI/BI/Expressions/Extensions/UserExt.cs index be007c86..a207ae61 100644 --- a/Disco.BI/BI/Expressions/Extensions/UserExt.cs +++ b/Disco.BI/BI/Expressions/Extensions/UserExt.cs @@ -1,10 +1,7 @@ -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; namespace Disco.BI.Expressions.Extensions { diff --git a/Disco.BI/BI/Extensions/ClientServicesExtensions.cs b/Disco.BI/BI/Extensions/ClientServicesExtensions.cs index 624b4ae7..954d02a3 100644 --- a/Disco.BI/BI/Extensions/ClientServicesExtensions.cs +++ b/Disco.BI/BI/Extensions/ClientServicesExtensions.cs @@ -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" }; diff --git a/Disco.BI/BI/Extensions/DeviceActionExtensions.cs b/Disco.BI/BI/Extensions/DeviceActionExtensions.cs index 498e5c49..131992ea 100644 --- a/Disco.BI/BI/Extensions/DeviceActionExtensions.cs +++ b/Disco.BI/BI/Extensions/DeviceActionExtensions.cs @@ -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 { @@ -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); } diff --git a/Disco.BI/BI/Extensions/DeviceExtensions.cs b/Disco.BI/BI/Extensions/DeviceExtensions.cs index bed7ff3d..6a41af35 100644 --- a/Disco.BI/BI/Extensions/DeviceExtensions.cs +++ b/Disco.BI/BI/Extensions/DeviceExtensions.cs @@ -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; @@ -10,14 +9,18 @@ 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, ActiveDirectoryDomain 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 +43,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 AvailableDocumentTemplates(this Device d, DiscoDataContext Database, User User, System.DateTime TimeStamp) { @@ -52,7 +56,7 @@ namespace Disco.BI.Extensions public static bool UpdateLastNetworkLogonDate(this Device Device) { - return ActiveDirectoryUpdateLastNetworkLogonDateJob.UpdateLastNetworkLogonDate(Device); + return Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.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) @@ -63,7 +67,7 @@ namespace Disco.BI.Extensions DeviceAttachment da = new DeviceAttachment() { DeviceSerialNumber = Device.SerialNumber, - TechUserId = CreatorUser.Id, + TechUserId = CreatorUser.UserId, Filename = Filename, MimeType = MimeType, Timestamp = DateTime.Now, @@ -160,12 +164,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 +178,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.RetrieveMachineAccount(d.DeviceDomainId); if (adMachineAccount != null) { adMachineAccount.SetDescription(d); @@ -188,8 +192,8 @@ namespace Disco.BI.Extensions public static ActiveDirectoryMachineAccount 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.RetrieveMachineAccount(Device.DeviceDomainId, AdditionalProperties: AdditionalProperties); else return null; } diff --git a/Disco.BI/BI/Extensions/DocumentTemplateExtensions.cs b/Disco.BI/BI/Extensions/DocumentTemplateExtensions.cs index 1fafd3e0..2f80a8e6 100644 --- a/Disco.BI/BI/Extensions/DocumentTemplateExtensions.cs +++ b/Disco.BI/BI/Extensions/DocumentTemplateExtensions.cs @@ -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"); } diff --git a/Disco.BI/BI/Extensions/JobActionExtensions.cs b/Disco.BI/BI/Extensions/JobActionExtensions.cs index ab368a2c..6bd1d4d3 100644 --- a/Disco.BI/BI/Extensions/JobActionExtensions.cs +++ b/Disco.BI/BI/Extensions/JobActionExtensions.cs @@ -41,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; @@ -64,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 @@ -83,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 @@ -106,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) }; @@ -133,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) }; @@ -178,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) }; @@ -248,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 }); @@ -258,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)) }; @@ -302,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 @@ -356,7 +356,7 @@ namespace Disco.BI.Extensions throw new InvalidOperationException("Close was Denied"); j.ClosedDate = DateTime.Now; - j.ClosedTechUserId = Technician.Id; + j.ClosedTechUserId = Technician.UserId; } private static bool CanCloseNever(this Job j, JobQueueJob IgnoreJobQueueJob = null) @@ -475,14 +475,14 @@ namespace Disco.BI.Extensions 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 diff --git a/Disco.BI/BI/Extensions/JobExtensions.cs b/Disco.BI/BI/Extensions/JobExtensions.cs index 97d4fbbc..629e4803 100644 --- a/Disco.BI/BI/Extensions/JobExtensions.cs +++ b/Disco.BI/BI/Extensions/JobExtensions.cs @@ -22,7 +22,7 @@ namespace Disco.BI.Extensions JobAttachment ja = new JobAttachment() { JobId = Job.Id, - TechUserId = CreatorUser.Id, + TechUserId = CreatorUser.UserId, Filename = Filename, MimeType = MimeType, Timestamp = DateTime.Now, @@ -148,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() }); @@ -182,7 +182,7 @@ namespace Disco.BI.Extensions Database.JobComponents.Add(new JobComponent() { Job = j, - TechUserId = TechUser.Id, + TechUserId = TechUser.UserId, Cost = c.Cost, Description = c.Description }); diff --git a/Disco.BI/BI/Extensions/JobQueueActionExtensions.cs b/Disco.BI/BI/Extensions/JobQueueActionExtensions.cs index e809fbc4..bd08f5a0 100644 --- a/Disco.BI/BI/Extensions/JobQueueActionExtensions.cs +++ b/Disco.BI/BI/Extensions/JobQueueActionExtensions.cs @@ -149,7 +149,7 @@ namespace Disco.BI.Extensions throw new InvalidOperationException("Removing job from queue is Denied"); jqj.RemovedDate = DateTime.Now; - jqj.RemovedUserId = Technician.Id; + jqj.RemovedUserId = Technician.UserId; jqj.RemovedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(); } #endregion @@ -201,7 +201,7 @@ namespace Disco.BI.Extensions JobQueueId = jq.Id, JobId = j.Id, AddedDate = DateTime.Now, - AddedUserId = Technician.Id, + AddedUserId = Technician.UserId, AddedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(), SLAExpiresDate = SLAExpires, Priority = Priority diff --git a/Disco.BI/BI/Extensions/UserExtensions.cs b/Disco.BI/BI/Extensions/UserExtensions.cs index 9bb2b402..de9572af 100644 --- a/Disco.BI/BI/Extensions/UserExtensions.cs +++ b/Disco.BI/BI/Extensions/UserExtensions.cs @@ -19,8 +19,8 @@ namespace Disco.BI.Extensions UserAttachment ua = new UserAttachment() { - UserId = User.Id, - TechUserId = CreatorUser.Id, + UserId = User.UserId, + TechUserId = CreatorUser.UserId, Filename = Filename, MimeType = MimeType, Timestamp = DateTime.Now, @@ -59,7 +59,7 @@ namespace Disco.BI.Extensions } public static ActiveDirectoryUserAccount ActiveDirectoryAccount(this User User, params string[] AdditionalProperties) { - return Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(User.Id, AdditionalProperties); + return Disco.Services.Interop.ActiveDirectory.ActiveDirectory.RetrieveUserAccount(User.UserId, AdditionalProperties); } public static bool CanCreateJob(this User u) diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectory.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectory.cs index 8251529e..aa3ba4e8 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectory.cs +++ b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectory.cs @@ -1,562 +1,562 @@ -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; +//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 +//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); + //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 (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); - } - } + // 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); - } - } - } + // 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]); + // 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); + // 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]; + // 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]); - } + // 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 additionalProperties = new Dictionary(); - if (AdditionalProperties != null) - foreach (string propertyName in AdditionalProperties) - { - var property = result.Properties[propertyName]; - var propertyValues = new List(); - for (int index = 0; index < property.Count; index++) - propertyValues.Add(property[index]); - additionalProperties.Add(propertyName, propertyValues.ToArray()); - } + // // Additional Properties + // Dictionary additionalProperties = new Dictionary(); + // if (AdditionalProperties != null) + // foreach (string propertyName in AdditionalProperties) + // { + // var property = result.Properties[propertyName]; + // var propertyValues = new List(); + // 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 - }; - } + // 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 + //#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)); + //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"); + // 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# + // // 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(); + // // 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 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); - } + // 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; - } + // 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 + //#region Users - private static readonly string[] UserLoadProperties = { - "name", - "distinguishedName", - "sAMAccountName", - "objectSid", - "displayName", - "sn", - "givenName", - "memberOf", - "primaryGroupID", - "mail", - "telephoneNumber" - }; - public static List SearchUsers(string term) - { - List users = new List(); - 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)(objectClass=user)(|(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); + //private static readonly string[] UserLoadProperties = { + // "name", + // "distinguishedName", + // "sAMAccountName", + // "objectSid", + // "displayName", + // "sn", + // "givenName", + // "memberOf", + // "primaryGroupID", + // "mail", + // "telephoneNumber" + // }; + //public static List SearchUsers(string term) + //{ + // List users = new List(); + // 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)(objectClass=user)(|(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(); + // 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().ToList(); - groupDistinguishedNames.Add(ActiveDirectoryCachedGroups.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid)); - List groups = ActiveDirectoryCachedGroups.GetGroups(groupDistinguishedNames).ToList(); + // int primaryGroupID = (int)result.Properties["primaryGroupID"][0]; + // string primaryGroupSid = ActiveDirectoryHelpers.ConvertBytesToSDDLString(ActiveDirectoryHelpers.BuildPrimaryGroupSid(objectSid, primaryGroupID)); + // var groupDistinguishedNames = result.Properties["memberOf"].Cast().ToList(); + // groupDistinguishedNames.Add(ActiveDirectoryCachedGroups.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid)); + // List 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# - //} + // //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 additionalProperties = new Dictionary(); - if (AdditionalProperties != null) - foreach (string propertyName in AdditionalProperties) - { - var property = result.Properties[propertyName]; - var propertyValues = new List(); - for (int index = 0; index < property.Count; index++) - propertyValues.Add(property[index]); - additionalProperties.Add(propertyName, propertyValues.ToArray()); - } + // // Additional Properties + // Dictionary additionalProperties = new Dictionary(); + // if (AdditionalProperties != null) + // foreach (string propertyName in AdditionalProperties) + // { + // var property = result.Properties[propertyName]; + // var propertyValues = new List(); + // 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)); + // 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 (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; - } - } - } + // 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 + //#endregion - #region Organisation Units + //#region Organisation Units - public static List GetOrganisationalUnitStructure() - { - ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit - { - Children = new System.Collections.Generic.List() - }; - string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName; + //public static List GetOrganisationalUnitStructure() + //{ + // ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit + // { + // Children = new System.Collections.Generic.List() + // }; + // 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() - }; - ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry()); - if (ChildOU.Children.Count == 0) - ChildOU.Children = null; - ParentOU.Children.Add(ChildOU); - } - } - } + // 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() + // }; + // ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry()); + // if (ChildOU.Children.Count == 0) + // ChildOU.Children = null; + // ParentOU.Children.Add(ChildOU); + // } + // } + // } - } + //} - #endregion + //#endregion - #region Groups + //#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)); + //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 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); - } - } + // 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); + // 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; - } - } - } + // 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 SearchGroups(string term) - { - List results = new List(); - 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; - } + //public static List SearchGroups(string term) + //{ + // List results = new List(); + // 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().ToList(); + //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().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().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().ToList(); - return new ActiveDirectoryGroup() - { - Name = name, - DistinguishedName = distinguishedName, - CommonName = cn, - SamAccountName = sAMAccountName, - SecurityIdentifier = objectSid, - MemberOf = memberOf - }; - } + // return new ActiveDirectoryGroup() + // { + // Name = name, + // DistinguishedName = distinguishedName, + // CommonName = cn, + // SamAccountName = sAMAccountName, + // SecurityIdentifier = objectSid, + // MemberOf = memberOf + // }; + //} - #endregion + //#endregion - private static readonly string[] ObjectLoadProperties = { "objectCategory" }; - private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray(); + //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)); + //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; - } - } - } - } -} + // 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; + // } + // } + //} +// } +//} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryGroupExtensions.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryGroupExtensions.cs deleted file mode 100644 index 8de7ad15..00000000 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryGroupExtensions.cs +++ /dev/null @@ -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> GetMembers(ActiveDirectoryGroup group) - { - throw new NotImplementedException(); - } - - } -} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryHelpers.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryHelpers.cs index cbf08808..e2dbed4c 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryHelpers.cs +++ b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryHelpers.cs @@ -1,198 +1,198 @@ -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; +//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 _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 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)); - } +//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 _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 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) - { +// 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(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 +// 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(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); +// internal static string ConvertBytesToSDDLString(byte[] SID) +// { +// SecurityIdentifier sID = new SecurityIdentifier(SID, 0); - return sID.ToString(); - } +// return sID.ToString(); +// } - internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString) - { - SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString); +// internal static byte[] ConvertSDDLStringToBytes(string SidSsdlString) +// { +// SecurityIdentifier sID = new SecurityIdentifier(SidSsdlString); - var sidBytes = new byte[sID.BinaryLength]; +// var sidBytes = new byte[sID.BinaryLength]; - sID.GetBinaryForm(sidBytes, 0); +// sID.GetBinaryForm(sidBytes, 0); - return sidBytes; - } +// return sidBytes; +// } - internal static byte[] BuildPrimaryGroupSid(byte[] UserSID, int PrimaryGroupId) - { - var groupSid = (byte[])UserSID.Clone(); +// 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; - } +// 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; - } +// return groupSid; +// } - internal static string ConvertBytesToBinarySidString(byte[] SID) - { - StringBuilder escapedSid = new StringBuilder(); +// internal static string ConvertBytesToBinarySidString(byte[] SID) +// { +// StringBuilder escapedSid = new StringBuilder(); - foreach (var sidByte in SID) - { - escapedSid.Append('\\'); - escapedSid.Append(sidByte.ToString("x2")); - } +// foreach (var sidByte in SID) +// { +// escapedSid.Append('\\'); +// escapedSid.Append(sidByte.ToString("x2")); +// } - return escapedSid.ToString(); - } +// 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(); - } - } - } -} +// 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(); +// } +// } +// } +//} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryMachineAccountExtensions.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryMachineAccountExtensions.cs deleted file mode 100644 index d3c7e404..00000000 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryMachineAccountExtensions.cs +++ /dev/null @@ -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 children = new List(); - 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; - } - - } -} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs index 06241629..3a9beda0 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs +++ b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs @@ -1,14 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +//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 Children { get; set; } - } -} +//namespace Disco.BI.Interop.ActiveDirectory +//{ +// public class ActiveDirectoryOrganisationalUnit +// { +// public string Name { get; set; } +// public string Path { get; set; } +// public List Children { get; set; } +// } +//} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUpdateLastNetworkLogonDateJob.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUpdateLastNetworkLogonDateJob.cs index 63ca1fe4..378a8099 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUpdateLastNetworkLogonDateJob.cs +++ b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUpdateLastNetworkLogonDateJob.cs @@ -1,264 +1,264 @@ -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 - { +//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 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)); +// public override void InitalizeScheduledTask(DiscoDataContext Database) +// { +// // ActiveDirectoryUpdateLastNetworkLogonDateJob @ 11:30pm +// TriggerBuilder triggerBuilder = TriggerBuilder.Create(). +// WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30)); - this.ScheduleTask(triggerBuilder); - } +// this.ScheduleTask(triggerBuilder); +// } - protected override void ExecuteTask() - { - int changeCount; +// 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"); - } +// 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() - }); - } +// 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; +// 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(); - } +// 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; - } - } - } - } +// 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 computerLastLogonDates = new System.Collections.Generic.Dictionary(); +// } +// } +// 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 computerLastLogonDates = new System.Collections.Generic.Dictionary(); - int progressDCCountTotal = ActiveDirectoryHelpers.DefaultDomainDCNames.Count; - int progressDCCount = 0; - double progressDCProgress = 0; - if (progressDCCountTotal > 0) - progressDCProgress = 90 / progressDCCountTotal; +// 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..."); +// 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()) - { +// 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); +// 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(); +// 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)); +// 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++; - } +// 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); +// 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; - } - } - } - } - } -} +// if (System.DateTime.Compare(d.LastNetworkLogonDate.Value, computerLastLogonDate) < 0) +// { +// d.LastNetworkLogonDate = computerLastLogonDate; +// } +// } +// else +// { +// d.LastNetworkLogonDate = computerLastLogonDate; +// } +// } +// } +// } +// } +//} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUserAccountExtensions.cs b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUserAccountExtensions.cs index d34e897c..faf5ea4d 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUserAccountExtensions.cs +++ b/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryUserAccountExtensions.cs @@ -1,37 +1,37 @@ -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; - } - } - } -} +//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; +// } +// } +// } +//} diff --git a/Disco.BI/BI/Interop/Pdf/PdfGenerator.cs b/Disco.BI/BI/Interop/Pdf/PdfGenerator.cs index 7669e45b..be89f65b 100644 --- a/Disco.BI/BI/Interop/Pdf/PdfGenerator.cs +++ b/Disco.BI/BI/Interop/Pdf/PdfGenerator.cs @@ -65,6 +65,10 @@ namespace Disco.BI.Interop.Pdf DataObjects = new object[DataObjectsIds.Length]; for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++) { + string dataObjectId = DataObjectsIds[idIndex]; + if (!dataObjectId.Contains('\\')) + dataObjectId = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + dataObjectId; + DataObjects[idIndex] = UserService.GetUser(DataObjectsIds[idIndex], Database, true); if (DataObjects[idIndex] == null) throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex])); @@ -122,7 +126,7 @@ namespace Disco.BI.Interop.Pdf if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase)) { 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 +136,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 +241,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); diff --git a/Disco.BI/BI/Interop/SignalRHandlers/HeldDeviceNotifications.cs b/Disco.BI/BI/Interop/SignalRHandlers/HeldDeviceNotifications.cs index 31233dbb..6f8c58d6 100644 --- a/Disco.BI/BI/Interop/SignalRHandlers/HeldDeviceNotifications.cs +++ b/Disco.BI/BI/Interop/SignalRHandlers/HeldDeviceNotifications.cs @@ -61,7 +61,7 @@ namespace Disco.BI.Interop.SignalRHandlers { User u = (User)e.Entity; - var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.Id); + var userDevices = e.Database.Devices.Where(d => d.AssignedUserId == u.UserId); foreach (var userDevice in userDevices) { diff --git a/Disco.BI/BI/Interop/SignalRHandlers/UserHeldDeviceNotifications.cs b/Disco.BI/BI/Interop/SignalRHandlers/UserHeldDeviceNotifications.cs index 6fd9a990..ec7f31c7 100644 --- a/Disco.BI/BI/Interop/SignalRHandlers/UserHeldDeviceNotifications.cs +++ b/Disco.BI/BI/Interop/SignalRHandlers/UserHeldDeviceNotifications.cs @@ -76,7 +76,7 @@ namespace Disco.BI.Interop.SignalRHandlers { User u = (User)e.Entity; - notificationContext.Connection.Broadcast(u.Id); + notificationContext.Connection.Broadcast(u.UserId); } } } diff --git a/Disco.BI/BI/JobBI/Utilities.cs b/Disco.BI/BI/JobBI/Utilities.cs index ae331ded..6e956c10 100644 --- a/Disco.BI/BI/JobBI/Utilities.cs +++ b/Disco.BI/BI/JobBI/Utilities.cs @@ -15,7 +15,7 @@ namespace Disco.BI.JobBI 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 @@ -61,7 +61,7 @@ namespace Disco.BI.JobBI JobQueueId = queue.queue.Id, Job = j, AddedDate = DateTime.Now, - AddedUserId = initialTech.Id, + AddedUserId = initialTech.UserId, AddedComment = commentBuilder.ToString(), SLAExpiresDate = queue.queue.DefaultSLAExpiry.HasValue ? (DateTime?)DateTime.Now.AddMinutes(queue.queue.DefaultSLAExpiry.Value) : null, Priority = JobQueuePriority.Normal @@ -110,7 +110,7 @@ namespace Disco.BI.JobBI Database.JobComponents.Add(new JobComponent() { Job = j, - TechUserId = initialTech.Id, + TechUserId = initialTech.UserId, Cost = c.Cost, Description = c.Description }); diff --git a/Disco.BI/Disco.BI.csproj b/Disco.BI/Disco.BI.csproj index 4de17cfa..9ce88965 100644 --- a/Disco.BI/Disco.BI.csproj +++ b/Disco.BI/Disco.BI.csproj @@ -175,10 +175,7 @@ - - - diff --git a/Disco.Client/Extensions/EnrolExtensions.cs b/Disco.Client/Extensions/EnrolExtensions.cs index 7ab10b39..6655c702 100644 --- a/Disco.Client/Extensions/EnrolExtensions.cs +++ b/Disco.Client/Extensions/EnrolExtensions.cs @@ -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; diff --git a/Disco.Client/Interop/SystemAudit.cs b/Disco.Client/Interop/SystemAudit.cs index c63c72ee..e0f1b760 100644 --- a/Disco.Client/Interop/SystemAudit.cs +++ b/Disco.Client/Interop/SystemAudit.cs @@ -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 { diff --git a/Disco.Data/Configuration/Modules/ActiveDirectoryConfiguration.cs b/Disco.Data/Configuration/Modules/ActiveDirectoryConfiguration.cs new file mode 100644 index 00000000..280a376b --- /dev/null +++ b/Disco.Data/Configuration/Modules/ActiveDirectoryConfiguration.cs @@ -0,0 +1,37 @@ +using Disco.Data.Repository; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Data.Configuration.Modules +{ + public class ActiveDirectoryConfiguration : ConfigurationBase + { + public ActiveDirectoryConfiguration(DiscoDataContext Database) : base(Database) { } + + public override string Scope + { + get { return "ActiveDirectory"; } + } + + public List SearchContainers + { + get + { + return GetFromJson>(null); + } + set + { + SetAsJson(value); + } + } + + public bool? SearchEntireForest + { + get { return GetFromJson(null); } + set { SetAsJson(value); } + } + } +} diff --git a/Disco.Data/Configuration/SystemConfiguration.cs b/Disco.Data/Configuration/SystemConfiguration.cs index 985b7bfb..dff88ca9 100644 --- a/Disco.Data/Configuration/SystemConfiguration.cs +++ b/Disco.Data/Configuration/SystemConfiguration.cs @@ -21,6 +21,7 @@ namespace Disco.Data.Configuration this.moduleDeviceProfilesConfiguration = new Lazy(() => new Modules.DeviceProfilesConfiguration(Database)); this.moduleOrganisationAddressesConfiguration = new Lazy(() => new Modules.OrganisationAddressesConfiguration(Database)); this.moduleJobPreferencesConfiguration = new Lazy(() => new Modules.JobPreferencesConfiguration(Database)); + this.moduleActiveDirectoryConfiguration = new Lazy(() => new Modules.ActiveDirectoryConfiguration(Database)); } #region Configuration Modules @@ -29,6 +30,7 @@ namespace Disco.Data.Configuration private Lazy moduleDeviceProfilesConfiguration; private Lazy moduleOrganisationAddressesConfiguration; private Lazy moduleJobPreferencesConfiguration; + private Lazy moduleActiveDirectoryConfiguration; public Modules.BootstrapperConfiguration Bootstrapper { @@ -58,6 +60,13 @@ namespace Disco.Data.Configuration return moduleJobPreferencesConfiguration.Value; } } + public Modules.ActiveDirectoryConfiguration ActiveDirectory + { + get + { + return moduleActiveDirectoryConfiguration.Value; + } + } #endregion diff --git a/Disco.Data/Disco.Data.csproj b/Disco.Data/Disco.Data.csproj index 19fbae17..be4d4ada 100644 --- a/Disco.Data/Disco.Data.csproj +++ b/Disco.Data/Disco.Data.csproj @@ -48,6 +48,7 @@ + ..\packages\Rx-Core.2.1.30214.0\lib\Net45\System.Reactive.Core.dll @@ -72,6 +73,7 @@ + @@ -130,6 +132,10 @@ 201402032322432_DBv12.cs + + + 201404080227546_DBv13.cs + @@ -181,6 +187,9 @@ 201402032322432_DBv12.cs + + 201404080227546_DBv13.cs + ResXFileCodeGenerator Resources.Designer.cs diff --git a/Disco.Data/Migrations/201404080227546_DBv13.Designer.cs b/Disco.Data/Migrations/201404080227546_DBv13.Designer.cs new file mode 100644 index 00000000..8895a408 --- /dev/null +++ b/Disco.Data/Migrations/201404080227546_DBv13.Designer.cs @@ -0,0 +1,27 @@ +// +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"); } + } + } +} diff --git a/Disco.Data/Migrations/201404080227546_DBv13.cs b/Disco.Data/Migrations/201404080227546_DBv13.cs new file mode 100644 index 00000000..8102146a --- /dev/null +++ b/Disco.Data/Migrations/201404080227546_DBv13.cs @@ -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)); + } + } +} diff --git a/Disco.Data/Migrations/201404080227546_DBv13.resx b/Disco.Data/Migrations/201404080227546_DBv13.resx new file mode 100644 index 00000000..6493e238 --- /dev/null +++ b/Disco.Data/Migrations/201404080227546_DBv13.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 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 + + \ No newline at end of file diff --git a/Disco.Data/Repository/DiscoDataSeeder.cs b/Disco.Data/Repository/DiscoDataSeeder.cs index 40d05f35..c5c17bc5 100644 --- a/Disco.Data/Repository/DiscoDataSeeder.cs +++ b/Disco.Data/Repository/DiscoDataSeeder.cs @@ -3,6 +3,9 @@ using System.Collections.Generic; using System.Linq; using System.Text; using Disco.Models.Repository; +using System.Data.SqlClient; +using System.DirectoryServices.ActiveDirectory; +using System.DirectoryServices; namespace Disco.Data.Repository { @@ -15,6 +18,9 @@ namespace Disco.Data.Repository Database.SeedDeviceProfiles(); Database.SeedJobTypes(); Database.SeedJobSubTypes(); + + // Migration Maintenance + Database.MigratePreDomainObjects(); } public static void SeedDeploymentId(this DiscoDataContext Database) @@ -304,5 +310,128 @@ namespace Disco.Data.Repository } } // End Added: 2013-02-07 G# + + #region Migrate Users SQL + private const string MigratePreDomainUsers_Sql = @"INSERT INTO [Users] SELECT @IdNew, u.DisplayName, u.Surname, u.GivenName, u.PhoneNumber, u.EmailAddress FROM [Users] u WHERE [Id]=@IdExisting; + +UPDATE [JobQueueJobs] SET [AddedUserId]=@IdNew WHERE [AddedUserId]=@IdExisting; +UPDATE [JobQueueJobs] SET [RemovedUserId]=@IdNew WHERE [RemovedUserId]=@IdExisting; + +UPDATE [DeviceAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting; + +UPDATE [Devices] SET [AssignedUserId]=@IdNew WHERE [AssignedUserId]=@IdExisting; + +UPDATE [DeviceUserAssignments] SET [AssignedUserId]=@IdNew WHERE [AssignedUserId]=@IdExisting; + +UPDATE [JobAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting; + +UPDATE [JobComponents] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting; + +UPDATE [JobLogs] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting; + +UPDATE [JobMetaInsurances] SET [ClaimFormSentUserId]=@IdNew WHERE [ClaimFormSentUserId]=@IdExisting; + +UPDATE [JobMetaNonWarranties] SET [AccountingChargeAddedUserId]=@IdNew WHERE [AccountingChargeAddedUserId]=@IdExisting; +UPDATE [JobMetaNonWarranties] SET [AccountingChargePaidUserId]=@IdNew WHERE [AccountingChargePaidUserId]=@IdExisting; +UPDATE [JobMetaNonWarranties] SET [AccountingChargeRequiredUserId]=@IdNew WHERE [AccountingChargeRequiredUserId]=@IdExisting; +UPDATE [JobMetaNonWarranties] SET [InvoiceReceivedUserId]=@IdNew WHERE [InvoiceReceivedUserId]=@IdExisting; +UPDATE [JobMetaNonWarranties] SET [PurchaseOrderRaisedUserId]=@IdNew WHERE [PurchaseOrderRaisedUserId]=@IdExisting; +UPDATE [JobMetaNonWarranties] SET [PurchaseOrderSentUserId]=@IdNew WHERE [PurchaseOrderSentUserId]=@IdExisting; + +UPDATE [Jobs] SET [ClosedTechUserId]=@IdNew WHERE [ClosedTechUserId]=@IdExisting; +UPDATE [Jobs] SET [DeviceHeldTechUserId]=@IdNew WHERE [DeviceHeldTechUserId]=@IdExisting; +UPDATE [Jobs] SET [DeviceReadyForReturnTechUserId]=@IdNew WHERE [DeviceReadyForReturnTechUserId]=@IdExisting; +UPDATE [Jobs] SET [DeviceReturnedTechUserId]=@IdNew WHERE [DeviceReturnedTechUserId]=@IdExisting; +UPDATE [Jobs] SET [OpenedTechUserId]=@IdNew WHERE [OpenedTechUserId]=@IdExisting; +UPDATE [Jobs] SET [UserId]=@IdNew WHERE [UserId]=@IdExisting; + +UPDATE [UserAttachments] SET [TechUserId]=@IdNew WHERE [TechUserId]=@IdExisting; +UPDATE [UserAttachments] SET [UserId]=@IdNew WHERE [UserId]=@IdExisting; + +DELETE [Users] WHERE [Id]=@IdExisting;"; + #endregion + public static void MigratePreDomainObjects(this DiscoDataContext Database) + { + if (Database.Users.Count(u => !u.UserId.Contains(@"\")) > 0) + { + // Determine Computer Domain + string netBiosName = null; + string defaultNamingContext; + using (Domain d = Domain.GetComputerDomain()) + { + string ldapPath = string.Format("LDAP://{0}/", d.Name); + string configurationNamingContext; + + using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE")) + { + defaultNamingContext = adRootDSE.Properties["defaultNamingContext"][0].ToString(); + configurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString(); + } + + using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + configurationNamingContext)) + { + var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", d.Name); + var configSearchLoadProperites = new string[] { "NetBIOSName" }; + + using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, configSearchLoadProperites, SearchScope.OneLevel)) + { + SearchResult configResult = configSearcher.FindOne(); + + if (configResult != null) + netBiosName = configResult.Properties["NetBIOSName"][0].ToString(); + else + netBiosName = null; + } + } + } + if (string.IsNullOrWhiteSpace(netBiosName)) + throw new InvalidOperationException("Unable to determine the Domains NetBIOS Name"); + + // MIGRATE SETTINGS + + // Authorization Roles + foreach (var authRole in Database.AuthorizationRoles.Where(ar => ar.SubjectIds != null).ToList()) + { + var ids = string.Join(",", authRole.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : string.Format("{0}\\{1}", netBiosName, id))); + if (ids != authRole.SubjectIds) + authRole.SubjectIds = ids; + } + // Job Queues + foreach (var jobQueue in Database.JobQueues.Where(jq => jq.SubjectIds != null).ToList()) + { + var ids = string.Join(",", jobQueue.SubjectIds.Split(',').Select(id => id.Contains('\\') ? id : string.Format("{0}\\{1}", netBiosName, id))); + if (ids != jobQueue.SubjectIds) + jobQueue.SubjectIds = ids; + } + // Device Profiles - OU + foreach (var deviceProfile in Database.DeviceProfiles.Where(dp => dp.OrganisationalUnit == null || !dp.OrganisationalUnit.Contains(@"DC=")).ToList()) + { + if (string.IsNullOrWhiteSpace(deviceProfile.OrganisationalUnit)) + deviceProfile.OrganisationalUnit = string.Format("CN=Computers,{0}", defaultNamingContext); + else + deviceProfile.OrganisationalUnit = string.Format("{0},{1}", deviceProfile.OrganisationalUnit, defaultNamingContext); + } + Database.SaveChanges(); + + // MIGRATE DEVICES + foreach (var device in Database.Devices.Where(d => d.DeviceDomainId != null && !d.DeviceDomainId.Contains(@"\")).ToList()) + { + device.DeviceDomainId = string.Format("{0}\\{1}", netBiosName, device.DeviceDomainId); + } + Database.SaveChanges(); + + // MIGRATE USERS + foreach (var user in Database.Users.Where(u => !u.UserId.Contains(@"\")).ToList()) + { + SqlParameter idExisting = new SqlParameter("@IdExisting", System.Data.SqlDbType.NVarChar, 50); + idExisting.Value = user.UserId; + + SqlParameter idNew = new SqlParameter("@IdNew", System.Data.SqlDbType.NVarChar, 50); + idNew.Value = string.Format("{0}\\{1}", netBiosName, user.UserId); + + Database.Database.ExecuteSqlCommand(MigratePreDomainUsers_Sql, idExisting, idNew); + } + } + } } } diff --git a/Disco.Models/ClientServices/Enrol.cs b/Disco.Models/ClientServices/Enrol.cs index 69c7893a..70af19d2 100644 --- a/Disco.Models/ClientServices/Enrol.cs +++ b/Disco.Models/ClientServices/Enrol.cs @@ -15,6 +15,7 @@ namespace Disco.Models.ClientServices public string DeviceSerialNumber { get; set; } public string DeviceUUID { get; set; } + public string DeviceDNSDomainName { get; set; } public string DeviceComputerName { get; set; } public bool DeviceIsPartOfDomain { get; set; } diff --git a/Disco.Models/Disco.Models.csproj b/Disco.Models/Disco.Models.csproj index c1b4979c..c80e285f 100644 --- a/Disco.Models/Disco.Models.csproj +++ b/Disco.Models/Disco.Models.csproj @@ -38,6 +38,7 @@ + @@ -46,6 +47,9 @@ + + + @@ -168,7 +172,7 @@ - + diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryDomain.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryDomain.cs new file mode 100644 index 00000000..d267cf90 --- /dev/null +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryDomain.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Models.Interop.ActiveDirectory +{ + public class ActiveDirectoryDomain + { + public string DnsName { get; private set; } + public string NetBiosName { get; private set; } + public string DistinguishedName { get; private set; } + + public List SearchContainers { get; private set; } + + public ActiveDirectoryDomain(string DnsName, string NetBiosName, string DistinguishedName, List SearchContainers) + { + this.DnsName = DnsName; + this.NetBiosName = NetBiosName; + this.DistinguishedName = DistinguishedName; + this.SearchContainers = SearchContainers; + } + + public void UpdateSearchContainers(IEnumerable Containers) + { + this.SearchContainers = Containers.ToList(); + } + } +} \ No newline at end of file diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryGroup.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryGroup.cs index 4f88d54e..bc0ed614 100644 --- a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryGroup.cs +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryGroup.cs @@ -1,19 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Collections.Generic; namespace Disco.Models.Interop.ActiveDirectory { public class ActiveDirectoryGroup : IActiveDirectoryObject { - public string Name { get; set; } - public string DistinguishedName { get; set; } + public string Domain { get; set; } public string SamAccountName { get; set; } + + public string DistinguishedName { get; set; } public string SecurityIdentifier { get; set; } public string CommonName { get; set; } + public string Name { get; set; } + public List MemberOf { get; set; } + + public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } } } } diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryMachineAccount.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryMachineAccount.cs index bf4ac261..0ed7dcab 100644 --- a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryMachineAccount.cs +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryMachineAccount.cs @@ -1,21 +1,23 @@ -using System; +using Disco.Models.Repository; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Disco.Models.Repository; namespace Disco.Models.Interop.ActiveDirectory { public class ActiveDirectoryMachineAccount : IActiveDirectoryObject { - public string DistinguishedName { get; set; } - public string DnsName { get; set; } + public string Domain { get; set; } - public string Name { get; set; } - public Guid NetbootGUID { get; set; } - public string SecurityIdentifier { get; set; } - public string Path { get; set; } public string SamAccountName { get; set; } + + public string SecurityIdentifier { get; set; } + public string DistinguishedName { get; set; } + public string Path { get; set; } + + public string Name { get; set; } + public string DnsName { get; set; } + public Guid NetbootGUID { get; set; } + public bool IsCriticalSystemObject { get; set; } public Dictionary LoadedProperties { get; set; } @@ -23,10 +25,11 @@ namespace Disco.Models.Interop.ActiveDirectory { return new User { - Id = this.SamAccountName, + UserId = this.Domain + "\\" + this.SamAccountName, DisplayName = this.Name }; } + public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } } } } diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs new file mode 100644 index 00000000..7cd01b77 --- /dev/null +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryOrganisationalUnit.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Models.Interop.ActiveDirectory +{ + public class ActiveDirectoryOrganisationalUnit + { + public string Name { get; set; } + public string Domain { get; set; } + public string DistinguishedName { get; set; } + public List Children { get; set; } + } +} diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectorySearchResult.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectorySearchResult.cs new file mode 100644 index 00000000..2b2be100 --- /dev/null +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectorySearchResult.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.DirectoryServices; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Models.Interop.ActiveDirectory +{ + public class ActiveDirectorySearchResult + { + public ActiveDirectoryDomain Domain { get; set; } + public string SearchRoot { get; set; } + public SearchResult Result { get; set; } + } +} diff --git a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryUserAccount.cs b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryUserAccount.cs index 7ba9ec5d..ef4b4db4 100644 --- a/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryUserAccount.cs +++ b/Disco.Models/Interop/ActiveDirectory/ActiveDirectoryUserAccount.cs @@ -8,25 +8,29 @@ namespace Disco.Models.Interop.ActiveDirectory { public class ActiveDirectoryUserAccount : IActiveDirectoryObject { - public string DisplayName { get; set; } - public string DistinguishedName { get; set; } public string Domain { get; set; } - public string Email { get; set; } - public string GivenName { get; set; } - public List Groups { get; set; } - public string Name { get; set; } + public string SamAccountName { get; set; } + + public string DistinguishedName { get; set; } public string SecurityIdentifier { get; set; } public string Path { get; set; } - public string Phone { get; set; } - public string SamAccountName { get; set; } + + public string Name { get; set; } + public string DisplayName { get; set; } + public string Email { get; set; } public string Surname { get; set; } + public string GivenName { get; set; } + public string Phone { get; set; } + + public List Groups { get; set; } + public Dictionary LoadedProperties { get; set; } public User ToRepositoryUser() { return new User { - Id = this.SamAccountName, + UserId = this.Domain + "\\" + this.SamAccountName, DisplayName = this.DisplayName, Surname = this.Surname, GivenName = this.GivenName, @@ -35,5 +39,6 @@ namespace Disco.Models.Interop.ActiveDirectory }; } + public string NetBiosId { get { return string.Format(@"{0}\{1}", Domain, SamAccountName); } } } } diff --git a/Disco.Models/Interop/ActiveDirectory/IActiveDirectoryObject.cs b/Disco.Models/Interop/ActiveDirectory/IActiveDirectoryObject.cs index 15db7abf..cd880385 100644 --- a/Disco.Models/Interop/ActiveDirectory/IActiveDirectoryObject.cs +++ b/Disco.Models/Interop/ActiveDirectory/IActiveDirectoryObject.cs @@ -1,17 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - + namespace Disco.Models.Interop.ActiveDirectory { public interface IActiveDirectoryObject { string DistinguishedName { get; set; } string SecurityIdentifier { get; set; } - + + string Domain { get; set; } string SamAccountName { get; set; } + string NetBiosId { get; } string Name { get; set; } } diff --git a/Disco.Models/Repository/Device/Device.cs b/Disco.Models/Repository/Device/Device.cs index 3588f15d..f46e4224 100644 --- a/Disco.Models/Repository/Device/Device.cs +++ b/Disco.Models/Repository/Device/Device.cs @@ -22,8 +22,8 @@ namespace Disco.Models.Repository public int DeviceProfileId { get; set; } public int? DeviceBatchId { get; set; } - [StringLength(24)] - public string ComputerName { get; set; } + [StringLength(50), Column("ComputerName")] + public string DeviceDomainId { get; set; } public string AssignedUserId { get; set; } public DateTime? LastNetworkLogonDate { get; set; } @@ -67,6 +67,26 @@ namespace Disco.Models.Repository return this.SerialNumber; } + [NotMapped] + public string ComputerName + { + get + { + var index = DeviceDomainId.IndexOf('\\'); + return index < 0 ? DeviceDomainId : DeviceDomainId.Substring(index + 1); + } + } + + [NotMapped] + public string ComputerDomainName + { + get + { + var index = DeviceDomainId.IndexOf('\\'); + return index < 0 ? null : DeviceDomainId.Substring(0, index); + } + } + public enum DecommissionReasons { EndOfLife = 0, diff --git a/Disco.Models/Repository/User/User.cs b/Disco.Models/Repository/User/User.cs index 544fcf61..9eedea26 100644 --- a/Disco.Models/Repository/User/User.cs +++ b/Disco.Models/Repository/User/User.cs @@ -9,8 +9,8 @@ namespace Disco.Models.Repository { public class User { - [StringLength(50), Key] - public string Id { get; set; } + [StringLength(50), Key, Column("Id")] + public string UserId { get; set; } [StringLength(200)] public string DisplayName { get; set; } @@ -30,14 +30,34 @@ namespace Disco.Models.Repository [InverseProperty("UserId")] public virtual IList Jobs { get; set; } + [NotMapped, Obsolete("Should be using Combined Domain\\User format - UserId")] + public string Id + { + get + { + var index = UserId.IndexOf('\\'); + return index < 0 ? UserId : UserId.Substring(index + 1); + } + } + + [NotMapped] + public string Domain + { + get + { + var index = UserId.IndexOf('\\'); + return index < 0 ? null : UserId.Substring(0, index); + } + } + public override string ToString() { - return string.Format("{0} ({1})", this.DisplayName, this.Id); + return string.Format("{0} ({1})", this.DisplayName, this.UserId); } public void UpdateSelf(User u) { - if (!this.Id.Equals(u.Id, StringComparison.InvariantCultureIgnoreCase)) + if (!this.UserId.Equals(u.UserId, StringComparison.InvariantCultureIgnoreCase)) throw new ArgumentException("User Id's do not match", "u"); if (this.Surname != u.Surname) diff --git a/Disco.Models/Services/Jobs/JobLists/JobTableItemModel.cs b/Disco.Models/Services/Jobs/JobLists/JobTableItemModel.cs index f7862859..ed161ef7 100644 --- a/Disco.Models/Services/Jobs/JobLists/JobTableItemModel.cs +++ b/Disco.Models/Services/Jobs/JobLists/JobTableItemModel.cs @@ -6,7 +6,8 @@ namespace Disco.Models.Services.Jobs.JobLists public class JobTableItemModel : JobSearchResultItem { public int JobId { get; set; } - + +#pragma warning disable 809 [Obsolete("Use [int] JobId instead")] public override string Id { @@ -20,6 +21,7 @@ namespace Disco.Models.Services.Jobs.JobLists this.JobId = int.Parse(value); } } +#pragma warning restore 618 public DateTime OpenedDate { get; set; } public DateTime? ClosedDate { get; set; } public string JobTypeId { get; set; } @@ -30,6 +32,7 @@ namespace Disco.Models.Services.Jobs.JobLists public int? DeviceAddressId { get; set; } public string DeviceAddress { get; set; } public string OpenedTechUserId { get; set; } + public string OpenedTechUserFriendlyId { get; set; } public string OpenedTechUserDisplayName { get; set; } public string StatusDescription { get; set; } public string StatusId { get; set; } diff --git a/Disco.Models/Services/Searching/DeviceSearchResultItem.cs b/Disco.Models/Services/Searching/DeviceSearchResultItem.cs index 9e328da6..b663b917 100644 --- a/Disco.Models/Services/Searching/DeviceSearchResultItem.cs +++ b/Disco.Models/Services/Searching/DeviceSearchResultItem.cs @@ -13,7 +13,7 @@ namespace Disco.Models.Services.Searching public string Id { get; set; } public string Type { get { return type; } } public string Description { get { return string.Format("{0} ({1})", this.Id, this.ComputerName); } } - public string ScoreValue { get { return string.Format("{0} {1} {2} {3}", this.Id, this.AssignedUserId, this.AssignedUserDisplayName, this.AssetNumber); } } + public string ScoreValue { get { return string.Format("{0} {1} {2} {3} {4}", this.Id, this.AssignedUserId.Substring(0, this.AssignedUserId.IndexOf('\\')), this.AssignedUserId, this.AssignedUserDisplayName, this.AssetNumber); } } public string AssetNumber { get; set; } public string AssignedUserDescription diff --git a/Disco.Models/Services/Searching/JobSearchResultItem.cs b/Disco.Models/Services/Searching/JobSearchResultItem.cs index 8f7b643c..4cf96f4a 100644 --- a/Disco.Models/Services/Searching/JobSearchResultItem.cs +++ b/Disco.Models/Services/Searching/JobSearchResultItem.cs @@ -13,11 +13,12 @@ namespace Disco.Models.Services.Searching public virtual string Id { get; set; } public string Type { get { return type; } } public string Description { get { return string.Format("{0} ({1}; {2})", this.Id, this.UserId, this.DeviceSerialNumber); } } - public string ScoreValue { get { return string.Format("{0} {1} {2} {3}", this.Id, this.UserId, this.DeviceSerialNumber, this.UserDisplayName); } } + public string ScoreValue { get { return string.Format("{0} {1} {2} {3} {4}", this.Id, this.UserId.Substring(0, this.UserId.IndexOf('\\')), this.UserId, this.DeviceSerialNumber, this.UserDisplayName); } } public string DeviceSerialNumber { get; set; } public string UserId { get; set; } + public string UserFriendlyId { get; set; } public string UserDisplayName { get; set; } } } diff --git a/Disco.Models/Services/Searching/UserSearchResultItem.cs b/Disco.Models/Services/Searching/UserSearchResultItem.cs index 8e073111..05843f81 100644 --- a/Disco.Models/Services/Searching/UserSearchResultItem.cs +++ b/Disco.Models/Services/Searching/UserSearchResultItem.cs @@ -13,7 +13,7 @@ namespace Disco.Models.Services.Searching public string Id { get; set; } public string Type { get { return type; } } public string Description { get { return string.Format("{0} ({1})", this.DisplayName, this.Id); } } - public string ScoreValue { get { return string.Format("{0} {1}", this.Id, this.DisplayName); } } + public string ScoreValue { get { return string.Format("{0} {1} {2}", this.Id.Substring(0, this.Id.IndexOf('\\')), this.Id, this.DisplayName); } } public int AssignedDevicesCount { get; set; } public string DisplayName { get; set; } diff --git a/Disco.Services/Authorization/Claims.cs b/Disco.Services/Authorization/Claims.cs index 5758cc6a..a29dee2d 100644 --- a/Disco.Services/Authorization/Claims.cs +++ b/Disco.Services/Authorization/Claims.cs @@ -59,6 +59,7 @@ namespace Disco.Services.Authorization { "Config.Plugin.Install", new Tuple, Action, string, string, bool>(c => c.Config.Plugin.Install, (c, v) => c.Config.Plugin.Install = v, "Install/Update Plugins", "Can install and update plugins", false) }, { "Config.Plugin.Show", new Tuple, Action, string, string, bool>(c => c.Config.Plugin.Show, (c, v) => c.Config.Plugin.Show = v, "Show Plugins", "Can show plugins", false) }, { "Config.Plugin.Uninstall", new Tuple, Action, string, string, bool>(c => c.Config.Plugin.Uninstall, (c, v) => c.Config.Plugin.Uninstall = v, "Uninstall Plugins", "Can uninstall plugins", false) }, + { "Config.System.ConfigureActiveDirectory", new Tuple, Action, string, string, bool>(c => c.Config.System.ConfigureActiveDirectory, (c, v) => c.Config.System.ConfigureActiveDirectory = v, "Configure Active Directory Settings", "Can configure the Active Directory interoperability settings", false) }, { "Config.System.ConfigureProxy", new Tuple, Action, string, string, bool>(c => c.Config.System.ConfigureProxy, (c, v) => c.Config.System.ConfigureProxy = v, "Configure Proxy Settings", "Can configure the proxy settings", false) }, { "Config.System.Show", new Tuple, Action, string, string, bool>(c => c.Config.System.Show, (c, v) => c.Config.System.Show = v, "Show System Configuration", "Can show the system configuration", false) }, { "Config.Organisation.ConfigureAddresses", new Tuple, Action, string, string, bool>(c => c.Config.Organisation.ConfigureAddresses, (c, v) => c.Config.Organisation.ConfigureAddresses = v, "Configure Addresses", "Can configure organisation addresses", false) }, @@ -286,6 +287,7 @@ namespace Disco.Services.Authorization new ClaimNavigatorItem("Config.Plugin.Uninstall", false) }), new ClaimNavigatorItem("Config.System", "System", "Permissions related to System Configuration", false, new List() { + new ClaimNavigatorItem("Config.System.ConfigureActiveDirectory", false), new ClaimNavigatorItem("Config.System.ConfigureProxy", false), new ClaimNavigatorItem("Config.System.Show", false) }), @@ -551,6 +553,7 @@ namespace Disco.Services.Authorization c.Config.Plugin.Install = true; c.Config.Plugin.Show = true; c.Config.Plugin.Uninstall = true; + c.Config.System.ConfigureActiveDirectory = true; c.Config.System.ConfigureProxy = true; c.Config.System.Show = true; c.Config.Organisation.ConfigureAddresses = true; @@ -956,6 +959,11 @@ namespace Disco.Services.Authorization public static class System { + /// Configure Active Directory Settings + /// Can configure the Active Directory interoperability settings + /// + public const string ConfigureActiveDirectory = "Config.System.ConfigureActiveDirectory"; + /// Configure Proxy Settings /// Can configure the proxy settings /// diff --git a/Disco.Services/Authorization/DiscoAuthorizeBaseAttribute.cs b/Disco.Services/Authorization/DiscoAuthorizeBaseAttribute.cs index fb268709..d2f0002a 100644 --- a/Disco.Services/Authorization/DiscoAuthorizeBaseAttribute.cs +++ b/Disco.Services/Authorization/DiscoAuthorizeBaseAttribute.cs @@ -39,7 +39,7 @@ namespace Disco.Services.Authorization // Log Access Denied if (Token != null) // Don't log anonymous - AuthorizationLog.LogAccessDenied(Token.User.Id, resultResource, resultMessage); + AuthorizationLog.LogAccessDenied(Token.User.UserId, resultResource, resultMessage); // Build Response View var ex = new AccessDeniedException(resultMessage, resultResource); diff --git a/Disco.Services/Authorization/Roles/ClaimGroups/Configuration/System/SystemClaims.cs b/Disco.Services/Authorization/Roles/ClaimGroups/Configuration/System/SystemClaims.cs index c54f9de8..5290e7a3 100644 --- a/Disco.Services/Authorization/Roles/ClaimGroups/Configuration/System/SystemClaims.cs +++ b/Disco.Services/Authorization/Roles/ClaimGroups/Configuration/System/SystemClaims.cs @@ -14,5 +14,8 @@ namespace Disco.Services.Authorization.Roles.ClaimGroups.Configuration.System [ClaimDetails("Configure Proxy Settings", "Can configure the proxy settings")] public bool ConfigureProxy { get; set; } + + [ClaimDetails("Configure Active Directory Settings", "Can configure the Active Directory interoperability settings")] + public bool ConfigureActiveDirectory { get; set; } } } diff --git a/Disco.Services/Authorization/Roles/RoleCache.cs b/Disco.Services/Authorization/Roles/RoleCache.cs index c8df3160..b06091dc 100644 --- a/Disco.Services/Authorization/Roles/RoleCache.cs +++ b/Disco.Services/Authorization/Roles/RoleCache.cs @@ -98,7 +98,7 @@ namespace Disco.Services.Authorization.Roles } internal static List GetRoleTokens(IEnumerable SecurityGroup, User User) { - var subjectIds = (new string[] { User.Id }).Concat(SecurityGroup).Select(sg => sg.ToLower()); + var subjectIds = (new string[] { User.UserId }).Concat(SecurityGroup).Select(sg => sg.ToLower()); return _Cache.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast().ToList(); } diff --git a/Disco.Services/Disco.Services.csproj b/Disco.Services/Disco.Services.csproj index 076e2e52..504fce15 100644 --- a/Disco.Services/Disco.Services.csproj +++ b/Disco.Services/Disco.Services.csproj @@ -174,6 +174,12 @@ + + + + + + @@ -240,7 +246,7 @@ - + diff --git a/Disco.Services/Interop/ActiveDirectory/ActiveDirectory.cs b/Disco.Services/Interop/ActiveDirectory/ActiveDirectory.cs new file mode 100644 index 00000000..7c75f604 --- /dev/null +++ b/Disco.Services/Interop/ActiveDirectory/ActiveDirectory.cs @@ -0,0 +1,531 @@ +using Disco.Data.Repository; +using Disco.Models.Interop.ActiveDirectory; +using Disco.Services.Interop.ActiveDirectory.Internal; +using System; +using System.Collections.Generic; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; +using System.Threading.Tasks; + +namespace Disco.Services.Interop.ActiveDirectory +{ + public static class ActiveDirectory + { + private const int SingleSearchResult = 1; + public const int MaxForestServerSearch = 30; + + public static void Initialize(DiscoDataContext Database) + { + ADInterop.Initialize(Database); + } + public static void UpdateSearchContainers(DiscoDataContext Database, List Containers) + { + ADInterop.UpdateSearchContainers(Database, Containers); + } + public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest) + { + return ADInterop.UpdateSearchEntireForest(Database, SearchEntireForest); + } + + public static ActiveDirectoryDomain PrimaryDomain + { + get + { + return ADInterop.PrimaryDomain; + } + } + public static IEnumerable Domains + { + get + { + return ADInterop.Domains.ToList(); + } + } + + public static ActiveDirectorySite Site + { + get + { + return ADInterop.Site; + } + } + + public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName) + { + return ADInterop.GetDomainByDistinguishedName(DistinguishedName); + } + + public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName) + { + return ADInterop.GetDomainByNetBiosName(NetBiosName); + } + + public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName) + { + return ADInterop.GetDomainByDnsName(DnsName); + } + + public static ActiveDirectoryDomain GetDomainFromId(string Id) + { + return ADInterop.GetDomainFromId(Id); + } + + public static List LoadForestServers() + { + return ADInterop.LoadForestServers(); + } + + public static Task> LoadForestServersAsync() + { + return ADInterop.LoadForestServersAsync(); + } + + public static bool SearchEntireForest + { + get + { + return ADInterop.SearchEntireForest; + } + } + + #region Machine Account + private static readonly string[] MachineLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" }; + + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, params string[] AdditionalProperties) + { + return RetrieveMachineAccount(DomainController, Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties); + } + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, params string[] AdditionalProperties) + { + return RetrieveMachineAccount(Id, (System.Guid?)null, (System.Guid?)null, AdditionalProperties); + } + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties) + { + return RetrieveMachineAccount(DomainController, Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties); + } + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, params string[] AdditionalProperties) + { + return RetrieveMachineAccount(Id, UUIDNetbootGUID, (System.Guid?)null, AdditionalProperties); + } + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties) + { + return RetrieveMachineAccount(null, Id, UUIDNetbootGUID, MacAddressNetbootGUID, AdditionalProperties); + } + public static ActiveDirectoryMachineAccount RetrieveMachineAccount(DomainController DomainController, string Id, System.Guid? UUIDNetbootGUID, System.Guid? MacAddressNetbootGUID, params string[] AdditionalProperties) + { + if (string.IsNullOrWhiteSpace(Id)) + throw new ArgumentNullException("Id"); + + // Add $ identifier for machine accounts + if (!Id.EndsWith("$")) + Id += "$"; + + const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))"; + const string ldapNetbootGuidFilterTemplate = "(&(objectCategory=computer)(netbootGUID={0}))"; + + string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0) + ? MachineLoadProperties.Concat(AdditionalProperties).ToArray() + : MachineLoadProperties; + + ActiveDirectorySearchResult adResult; + + var splitId = UserExtensions.SplitUserId(Id); + var ldapSamAccountFilter = string.Format(ldapFilterTemplate, splitId.Item2); + var domain = ADInterop.GetDomainFromId(Id); + + adResult = ADInterop.SearchAll(domain, DomainController, ldapSamAccountFilter, SingleSearchResult, loadProperites).FirstOrDefault(); + if (adResult == null && (UUIDNetbootGUID.HasValue || MacAddressNetbootGUID.HasValue)) + { + + if (UUIDNetbootGUID.HasValue) + { + var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)); + adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault(); + } + if (adResult == null && MacAddressNetbootGUID.HasValue) + { + var ldapFilter = string.Format(ldapNetbootGuidFilterTemplate, ADInterop.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)); + adResult = ADInterop.SearchAll(domain, DomainController, ldapFilter, SingleSearchResult, loadProperites).FirstOrDefault(); + } + } + + if (adResult != null) + return adResult.AsMachineAccount(AdditionalProperties); + else + return null; // Not Found + } + + private static ActiveDirectoryMachineAccount AsMachineAccount(this ActiveDirectorySearchResult item, string[] AdditionalProperties) + { + string name = item.Result.Properties["name"][0].ToString(); + string sAMAccountName = item.Result.Properties["sAMAccountName"][0].ToString(); + string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString(); + string objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]); + + var dNSNameProperty = item.Result.Properties["dNSHostName"]; + string dNSName = null; + if (dNSNameProperty.Count > 0) + dNSName = dNSNameProperty[0].ToString(); + else + dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), item.Domain.DnsName); + + bool isCriticalSystemObject = (bool)item.Result.Properties["isCriticalSystemObject"][0]; + + System.Guid netbootGUIDResult = default(System.Guid); + ResultPropertyValueCollection netbootGUIDProp = item.Result.Properties["netbootGUID"]; + if (netbootGUIDProp.Count > 0) + { + netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]); + } + + // Additional Properties + Dictionary additionalProperties = new Dictionary(); + if (AdditionalProperties != null) + foreach (string propertyName in AdditionalProperties) + { + var property = item.Result.Properties[propertyName]; + var propertyValues = new List(); + 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 = item.Result.Path, + Domain = item.Domain.NetBiosName, + DnsName = dNSName, + IsCriticalSystemObject = isCriticalSystemObject, + LoadedProperties = additionalProperties + }; + } + + public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerName, string OrganisationalUnit, ref ActiveDirectoryMachineAccount MachineAccount, out string DiagnosticInformation) + { + const string ldapFilterTemplate = "(&(objectCategory=computer)(sAMAccountName={0}))"; + + if (MachineAccount != null && MachineAccount.IsCriticalSystemObject) + throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", MachineAccount.DistinguishedName)); + + if (MachineAccount != null) + MachineAccount.DeleteAccount(DomainController); + + var computerId = UserExtensions.SplitUserId(ComputerName); + + var offlineJoinResult = ADInterop.OfflineDomainJoinProvision(Domain, DomainController, computerId.Item2, OrganisationalUnit, out DiagnosticInformation); + + // Reload newly created Account + string[] loadAdditionalProperties = (MachineAccount != null && MachineAccount.LoadedProperties != null && MachineAccount.LoadedProperties.Count > 0) + ? MachineAccount.LoadedProperties.Keys.ToArray() + : null; + + MachineAccount = null; + + string[] loadProperites = (loadAdditionalProperties != null) + ? MachineLoadProperties.Concat(loadAdditionalProperties).ToArray() + : MachineLoadProperties; + + var ldapSamAccountName = computerId.Item2.EndsWith("$") ? computerId.Item2 : computerId.Item2 + "$"; + var ldapFilter = string.Format(ldapFilterTemplate, ldapSamAccountName); + var ldapResult = ADInterop.SearchDomain(Domain, DomainController, Domain.DistinguishedName, ldapFilter, 1, loadProperites).FirstOrDefault(); + + if (ldapResult != null) + MachineAccount = ldapResult.AsMachineAccount(loadAdditionalProperties); + + return offlineJoinResult; + } + + #endregion + + #region User Account + private static readonly string[] UserLoadProperties = { "name", "distinguishedName", "sAMAccountName", "objectSid", "displayName", "sn", "givenName", "memberOf", "primaryGroupID", "mail", "telephoneNumber" }; + + public static ActiveDirectoryUserAccount RetrieveUserAccount(string Id, params string[] AdditionalProperties) + { + const string ldapFilter = "(&(objectCategory=Person)(sAMAccountName={0}))"; + + string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0) + ? UserLoadProperties.Concat(AdditionalProperties).ToArray() + : UserLoadProperties; + + return SearchBySamAccountName(Id, ldapFilter, loadProperites).Select(result => result.AsUserAccount(AdditionalProperties)).FirstOrDefault(); + } + public static IEnumerable SearchUserAccounts(string Term, params string[] AdditionalProperties) + { + const int resultLimit = 30; // Default Search Limit + + if (string.IsNullOrWhiteSpace(Term)) + throw new ArgumentNullException("Term"); + + string ldapFilter = string.Format("(&(objectCategory=Person)(objectClass=user)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", ADInterop.EscapeLdapQuery(Term)); + + string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0) + ? UserLoadProperties.Concat(AdditionalProperties).ToArray() + : UserLoadProperties; + + return ADInterop.SearchScope(ldapFilter, resultLimit, loadProperites).Select(result => result.AsUserAccount(AdditionalProperties)); + } + + private static ActiveDirectoryUserAccount AsUserAccount(this ActiveDirectorySearchResult item, string[] AdditionalProperties) + { + string name = item.Result.Properties["name"][0].ToString(); + string username = item.Result.Properties["sAMAccountName"][0].ToString(); + string distinguishedName = item.Result.Properties["distinguishedName"][0].ToString(); + byte[] objectSid = (byte[])item.Result.Properties["objectSid"][0]; + string objectSidSDDL = ADInterop.ConvertBytesToSDDLString(objectSid); + + ResultPropertyValueCollection displayNameProp = item.Result.Properties["displayName"]; + string displayName = username; + if (displayNameProp.Count > 0) + displayName = displayNameProp[0].ToString(); + string surname = null; + ResultPropertyValueCollection surnameProp = item.Result.Properties["sn"]; + if (surnameProp.Count > 0) + surname = surnameProp[0].ToString(); + string givenName = null; + ResultPropertyValueCollection givenNameProp = item.Result.Properties["givenName"]; + if (givenNameProp.Count > 0) + givenName = givenNameProp[0].ToString(); + string email = null; + ResultPropertyValueCollection emailProp = item.Result.Properties["mail"]; + if (emailProp.Count > 0) + email = emailProp[0].ToString(); + string phone = null; + ResultPropertyValueCollection phoneProp = item.Result.Properties["telephoneNumber"]; + if (phoneProp.Count > 0) + phone = phoneProp[0].ToString(); + + int primaryGroupID = (int)item.Result.Properties["primaryGroupID"][0]; + string primaryGroupSid = ADInterop.ConvertBytesToSDDLString(ADInterop.BuildPrimaryGroupSid(objectSid, primaryGroupID)); + var groupDistinguishedNames = item.Result.Properties["memberOf"].Cast().ToList(); + groupDistinguishedNames.Add(ADGroupCache.GetGroupsDistinguishedNameForSecurityIdentifier(primaryGroupSid)); + List groups = ADGroupCache.GetGroups(groupDistinguishedNames).ToList(); + + // Additional Properties + Dictionary additionalProperties = new Dictionary(); + if (AdditionalProperties != null) + foreach (string propertyName in AdditionalProperties) + { + var property = item.Result.Properties[propertyName]; + var propertyValues = new List(); + for (int index = 0; index < property.Count; index++) + propertyValues.Add(property[index]); + additionalProperties.Add(propertyName, propertyValues.ToArray()); + } + + return new ActiveDirectoryUserAccount + { + Domain = item.Domain.NetBiosName, + Name = name, + Surname = surname, + GivenName = givenName, + Email = email, + Phone = phone, + DistinguishedName = distinguishedName, + SamAccountName = username, + DisplayName = displayName, + SecurityIdentifier = objectSidSDDL, + Groups = groups, + Path = item.Result.Path, + LoadedProperties = additionalProperties + }; + } + #endregion + + #region Groups + private static readonly string[] GroupLoadProperties = { "name", "distinguishedName", "cn", "sAMAccountName", "objectSid", "memberOf" }; + + public static ActiveDirectoryGroup RetrieveGroup(string Id) + { + const string ldapFilter = "(&(objectCategory=Group)(objectSid={0}))"; + + return SearchBySamAccountName(Id, ldapFilter, GroupLoadProperties).Select(result => result.AsGroup()).FirstOrDefault(); + } + public static ActiveDirectoryGroup RetrieveGroupWithDistinguishedName(string DistinguishedName) + { + ActiveDirectoryDomain domain; + + using (var groupEntry = ADInterop.RetrieveDirectoryEntry(DistinguishedName, out domain)) + { + if (groupEntry == null) + return null; + + return groupEntry.AsGroup(domain); + } + } + public static ActiveDirectoryGroup RetrieveGroupWithSecurityIdentifier(string SecurityIdentifier) + { + const int resultLimit = 1; + + if (string.IsNullOrWhiteSpace(SecurityIdentifier)) + throw new ArgumentNullException("SecurityIdentifier"); + + var sidBytes = ADInterop.ConvertSDDLStringToBytes(SecurityIdentifier); + var sidBinaryString = ADInterop.ConvertBytesToBinarySidString(sidBytes); + + string ldapFilter = string.Format("(&(objectCategory=Group)(objectSid={0}))", sidBinaryString); + + return ADInterop.SearchAll(ldapFilter, resultLimit, null).Select(result => result.AsGroup()).FirstOrDefault(); + } + public static IEnumerable SearchGroups(string Term) + { + const int resultLimit = 30; // Default Search Limit + + if (string.IsNullOrWhiteSpace(Term)) + throw new ArgumentNullException("Term"); + + string ldapFilter = string.Format("(&(objectCategory=Group)(|(sAMAccountName=*{0}*)(name=*{0}*)(cn=*{0}*)))", ADInterop.EscapeLdapQuery(Term)); + + return ADInterop.SearchScope(ldapFilter, resultLimit, GroupLoadProperties).Select(result => result.AsGroup()); + } + + private static ActiveDirectoryGroup AsGroup(this ActiveDirectorySearchResult item) + { + var name = (string)item.Result.Properties["name"][0]; + var distinguishedName = (string)item.Result.Properties["distinguishedName"][0]; + var cn = (string)item.Result.Properties["cn"][0]; + var sAMAccountName = (string)item.Result.Properties["sAMAccountName"][0]; + var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Result.Properties["objectSid"][0]); + var memberOf = item.Result.Properties["memberOf"].Cast().ToList(); + + return new ActiveDirectoryGroup() + { + Domain = item.Domain.DnsName, + Name = name, + DistinguishedName = distinguishedName, + CommonName = cn, + SamAccountName = sAMAccountName, + SecurityIdentifier = objectSid, + MemberOf = memberOf + }; + } + private static ActiveDirectoryGroup AsGroup(this DirectoryEntry item, ActiveDirectoryDomain Domain) + { + var name = (string)item.Properties["name"][0]; + var distinguishedName = (string)item.Properties["distinguishedName"][0]; + var cn = (string)item.Properties["cn"][0]; + var sAMAccountName = (string)item.Properties["sAMAccountName"][0]; + var objectSid = ADInterop.ConvertBytesToSDDLString((byte[])item.Properties["objectSid"][0]); + var memberOf = item.Properties["memberOf"].Cast().ToList(); + + return new ActiveDirectoryGroup() + { + Domain = Domain.DnsName, + Name = name, + DistinguishedName = distinguishedName, + CommonName = cn, + SamAccountName = sAMAccountName, + SecurityIdentifier = objectSid, + MemberOf = memberOf + }; + } + #endregion + + #region Object + private static readonly string[] ObjectLoadProperties = { "objectCategory" }; + private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(UserLoadProperties).Concat(MachineLoadProperties).Concat(GroupLoadProperties).Distinct().ToArray(); + + public static IActiveDirectoryObject RetrieveObject(string Id) + { + const string ldapFilter = "(&(|(objectCategory=Person)(objectCategory=Computer)(objectCategory=Group))(sAMAccountName={0}))"; + + return SearchBySamAccountName(Id, ldapFilter, ObjectLoadPropertiesAll) + .Select(result => + { + var objectCategory = (string)result.Result.Properties["objectCategory"][0]; + objectCategory = objectCategory.Substring(0, objectCategory.IndexOf(',')).ToLower(); + switch (objectCategory) + { + case "cn=person": + return result.AsUserAccount(null); + case "cn=computer": + return result.AsMachineAccount(null); + case "cn=group": + return result.AsGroup(); + default: + throw new InvalidOperationException("Unexpected objectCategory"); + } + }).FirstOrDefault(); + } + #endregion + + #region Organisation Units + + public static List RetrieveOrganisationalUnitStructure(ActiveDirectoryDomain Domain) + { + using (DirectoryEntry domainRoot = ADInterop.RetrieveDirectoryEntry(Domain.DistinguishedName, out Domain)) + { + return ActiveDirectory.RetrieveOrganisationalUnitStructureInternal(Domain, domainRoot); + } + } + private static List RetrieveOrganisationalUnitStructureInternal(ActiveDirectoryDomain Domain, DirectoryEntry Container) + { + Dictionary> resultTree = new Dictionary>(); + + using (DirectorySearcher adSearcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[] + { + "name", + "distinguishedName" + }, SearchScope.Subtree)) + { + adSearcher.PageSize = 500; + + using (SearchResultCollection adResults = adSearcher.FindAll()) + { + resultTree = adResults.Cast().Select(adResult => + { + string i = adResult.Properties["name"][0].ToString(); + string dn = adResult.Properties["distinguishedName"][0].ToString(); + return new ActiveDirectoryOrganisationalUnit + { + Domain = Domain.NetBiosName, + Name = i, + DistinguishedName = dn, + }; + }).GroupBy(ou => ou.DistinguishedName.Substring(ou.DistinguishedName.IndexOf(',') + 1)).ToDictionary(g => g.Key, g => g.ToList()); + } + } + + // Build Tree + var results = resultTree[Domain.DistinguishedName]; + foreach (var child in results) + RetrieveOrganisationalUnitStructureChildrenInternal(child, resultTree); + + return results; + } + private static void RetrieveOrganisationalUnitStructureChildrenInternal(ActiveDirectoryOrganisationalUnit OrganisationalUnit, Dictionary> ResultTree) + { + List children; + + if (ResultTree.TryGetValue(OrganisationalUnit.DistinguishedName, out children)) + { + foreach (var child in children) + RetrieveOrganisationalUnitStructureChildrenInternal(child, ResultTree); + + OrganisationalUnit.Children = children; + } + } + + #endregion + + #region Helpers + + private static IEnumerable SearchBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties) + { + var splitId = UserExtensions.SplitUserId(Id); + var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2); + var domains = ADInterop.GetDomainFromId(Id); + + return ADInterop.SearchAll(domains, ldapFilter, SingleSearchResult, LoadProperties); + } + + #endregion + + } +} \ No newline at end of file diff --git a/Disco.Services/Interop/ActiveDirectory/ActiveDirectoryExtensions.cs b/Disco.Services/Interop/ActiveDirectory/ActiveDirectoryExtensions.cs new file mode 100644 index 00000000..ce196e62 --- /dev/null +++ b/Disco.Services/Interop/ActiveDirectory/ActiveDirectoryExtensions.cs @@ -0,0 +1,391 @@ +using Disco.Models.Interop.ActiveDirectory; +using Disco.Models.Repository; +using Disco.Services.Interop.ActiveDirectory.Internal; +using System; +using System.Collections.Generic; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Services.Interop.ActiveDirectory +{ + public static class ActiveDirectoryExtensions + { + #region Domain/Directory Extensions + + public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain) + { + return ADInterop.RetrieveWritableDomainController(domain); + } + + public static IEnumerable RetrieveReachableDomainControllers(this ActiveDirectorySite site, ActiveDirectoryDomain domain) + { + return site.Servers.OfType().Where(dc => dc.Reachable() && dc.Domain.Name.Equals(domain.DnsName)); + } + + public static IEnumerable RetrieveReachableDomainControllers(this ActiveDirectoryDomain domain) + { + var d = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domain.DnsName)); + return d.FindAllDomainControllers().OfType().Where(dc => dc.Reachable()); + } + + public static bool Reachable(this DirectoryServer ds) + { + using (Ping p = new Ping()) + { + var pr = p.Send(ds.Name, 500); + return (pr.Status == IPStatus.Success); + } + } + + public static string GetFriendlyOrganisationalUnitName(this ActiveDirectoryDomain domain, string DistinguishedName) + { + if (!DistinguishedName.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase)) + throw new ArgumentException(string.Format("The Distinguished Name [{0}] doesn't exist within this domain [{1}]", DistinguishedName, domain.DistinguishedName)); + + StringBuilder name = new StringBuilder(); + + name.Append('[').Append(domain.NetBiosName).Append(']'); + + var subDN = DistinguishedName.Substring(0, DistinguishedName.Length - domain.DistinguishedName.Length); + var subDNComponents = subDN.Split(','); + + subDNComponents + .Where(c => !string.IsNullOrWhiteSpace(c)) + .Reverse() + .Select(c => c.Substring(c.IndexOf('=') + 1)) + .ToList() + .ForEach(c => name.Append(" > ").Append(c)); + + return name.ToString(); + } + + public static string GetDefaultComputerContainer(this ActiveDirectoryDomain domain) + { + return string.Format("CN=Computers,{0}", domain.DistinguishedName); + } + + #endregion + + #region User Account Extensions + 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; + } + } + #endregion + + #region Machine Account Extensions + + public static void DeleteAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController) + { + 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 deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + deAccount.DeleteObjectRecursive(); + } + } + public static void DeleteAccount(this ActiveDirectoryMachineAccount account) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + account.DeleteAccount(domainController); + } + } + + private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, 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 deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + PropertyValueCollection netbootGUIDProp = deAccount.Properties["netbootGUID"]; + bool flag = netbootGUIDProp.Count > 0; + if (flag) + { + netbootGUIDProp.Clear(); + } + netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray()); + deAccount.CommitChanges(); + } + } + public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, string Description) + { + using (DirectoryEntry deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + PropertyValueCollection descriptionProp = deAccount.Properties["description"]; + if (descriptionProp.Count > 0) + { + descriptionProp.Clear(); + } + if (!string.IsNullOrEmpty(Description)) + { + descriptionProp.Add(Description); + } + deAccount.CommitChanges(); + } + } + public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + account.SetDescription(domainController, Description); + } + } + + public static void SetDescription(this ActiveDirectoryMachineAccount account, DomainController DomainController, Device Device) + { + System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder(); + + if (Device.AssignedUserId != null) + { + descriptionBuilder.Append(Device.AssignedUser.UserId).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(DomainController, description); + } + public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + account.SetDescription(domainController, Device); + } + } + + public static void DisableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController) + { + 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 deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + int accountControl = (int)deAccount.Properties["userAccountControl"][0]; + int updatedAccountControl = (accountControl | 2); + if (accountControl != updatedAccountControl) + { + deAccount.Properties["userAccountControl"][0] = updatedAccountControl; + deAccount.CommitChanges(); + } + } + } + public static void DisableAccount(this ActiveDirectoryMachineAccount account) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + account.DisableAccount(domainController); + } + } + public static void EnableAccount(this ActiveDirectoryMachineAccount account, DomainController DomainController) + { + 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 deAccount = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + int accountControl = (int)deAccount.Properties["userAccountControl"][0]; + if ((accountControl & 2) == 2) + { + int updatedAccountControl = (accountControl ^ 2); + deAccount.Properties["userAccountControl"][0] = updatedAccountControl; + deAccount.CommitChanges(); + } + } + } + public static void EnableAccount(this ActiveDirectoryMachineAccount account) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + account.EnableAccount(domainController); + } + } + + public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, DomainController DomainController, 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)); + + Guid netbootGUID = Guid.Empty; + + if (!string.IsNullOrWhiteSpace(UUID)) + { + netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromUUID(UUID); + } + else if (!string.IsNullOrWhiteSpace(MACAddress)) + { + netbootGUID = ActiveDirectoryExtensions.NetbootGUIDFromMACAddress(MACAddress); + } + + if (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID) + { + account.SetNetbootGUID(DomainController, netbootGUID); + return true; + } + else + { + return false; + } + } + public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress) + { + var domain = account.GetDomain(); + + using (var domainController = domain.RetrieveWritableDomainController()) + { + return account.UpdateNetbootGUID(domainController, UUID, MACAddress); + } + } + public 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; + } + public 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; + } + } + + public static void MoveOrganisationalUnit(this ActiveDirectoryMachineAccount account, DomainController DomainController, 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)) + { + var domain = account.GetDomain(); + + // If no OU provided, place in default Computers container + if (string.IsNullOrWhiteSpace(NewOrganisationUnit)) + NewOrganisationUnit = domain.GetDefaultComputerContainer(); + + if (!NewOrganisationUnit.EndsWith(domain.DistinguishedName, StringComparison.InvariantCultureIgnoreCase)) + throw new InvalidOperationException(string.Format("Unable to move AD Account from one domain [{0}] to another [{1}].", account.DistinguishedName, NewOrganisationUnit)); + + using (DirectoryEntry ou = DomainController.RetrieveDirectoryEntry(NewOrganisationUnit)) + { + using (DirectoryEntry i = DomainController.RetrieveDirectoryEntry(account.DistinguishedName)) + { + i.UsePropertyCache = false; + i.MoveTo(ou); + } + } + } + } + + public static string ParentDistinguishedName(this ActiveDirectoryMachineAccount account) + { + // Determine Parent + if (!string.IsNullOrWhiteSpace(account.DistinguishedName)) + return account.DistinguishedName.Substring(account.DistinguishedName.IndexOf(",") + 1); + else + return null; + } + + public static ActiveDirectoryDomain GetDomain(this ActiveDirectoryMachineAccount account) + { + var domain = ActiveDirectory.GetDomainByNetBiosName(account.Domain); + + if (domain == null) + throw new InvalidOperationException(string.Format("Unable to find Domain [{0}] for account [{1}]", account.Domain, account.Name)); + else + return domain; + } + + #endregion + } +} diff --git a/Disco.Services/Interop/ActiveDirectory/Internal/ADDiscoverForestServers.cs b/Disco.Services/Interop/ActiveDirectory/Internal/ADDiscoverForestServers.cs new file mode 100644 index 00000000..d0631b76 --- /dev/null +++ b/Disco.Services/Interop/ActiveDirectory/Internal/ADDiscoverForestServers.cs @@ -0,0 +1,68 @@ +using Disco.Data.Repository; +using Disco.Services.Tasks; +using System; +using System.Collections.Generic; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Services.Interop.ActiveDirectory.Internal +{ + public class ADDiscoverForestServers : ScheduledTask + { + public override string TaskName { get { return "Active Directory - Discover Forest Servers"; } } + public override bool SingleInstanceTask { get { return true; } } + public override bool CancelInitiallySupported { get { return false; } } + + protected override void ExecuteTask() + { + var forestServers = DiscoverForestServers(); + ADInterop._ForestServers = forestServers; + + // Restrict Searching Entire Forest if to many servers + using (DiscoDataContext Database = new DiscoDataContext()) + { + var searchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest; + + // Check explicitly configured: No + if (!searchEntireForest.HasValue || searchEntireForest.Value) + { + // Not Configured, or explicitly configured: Yes + if (forestServers.Count > ActiveDirectory.MaxForestServerSearch) + { + // Update Database + Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false; + } + else + { + // Default + Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true; + } + + Database.SaveChanges(); + } + } + } + + internal static ScheduledTaskStatus ScheduleNow() + { + var taskStatus = ScheduledTasks.GetTaskStatuses(typeof(ADDiscoverForestServers)).Where(ts => ts.IsRunning).FirstOrDefault(); + if (taskStatus != null) + return taskStatus; + else + { + var t = new ADDiscoverForestServers(); + return t.ScheduleTask(); + } + } + + internal static List DiscoverForestServers() + { + using (var computerDomain = Domain.GetComputerDomain()) + { + return computerDomain.Forest.Domains.Cast().SelectMany(d => d.FindAllDomainControllers().Cast()).Select(dc => dc.Name).ToList(); + } + } + } +} diff --git a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryCachedGroups.cs b/Disco.Services/Interop/ActiveDirectory/Internal/ADGroupCache.cs similarity index 95% rename from Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryCachedGroups.cs rename to Disco.Services/Interop/ActiveDirectory/Internal/ADGroupCache.cs index abbb510a..fd4ef188 100644 --- a/Disco.BI/BI/Interop/ActiveDirectory/ActiveDirectoryCachedGroups.cs +++ b/Disco.Services/Interop/ActiveDirectory/Internal/ADGroupCache.cs @@ -1,18 +1,15 @@ -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.Data.Repository; +using Disco.Models.Interop.ActiveDirectory; using Disco.Services.Tasks; using Quartz; -using Disco.Models.Interop.ActiveDirectory; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; -namespace Disco.BI.Interop.ActiveDirectory +namespace Disco.Services.Interop.ActiveDirectory.Internal { - public class ActiveDirectoryCachedGroups : ScheduledTask + public class ADGroupCache : ScheduledTask { private static ConcurrentDictionary> _SecurityIdentifierCache = new ConcurrentDictionary>(); private static ConcurrentDictionary> _DistinguishedNameCache = new ConcurrentDictionary>(); @@ -72,7 +69,7 @@ namespace Disco.BI.Interop.ActiveDirectory if (groupRecord == null) { // Load from AD - var group = ActiveDirectory.GetGroupFromDistinguishedName(DistinguishedName); + var group = ActiveDirectory.RetrieveGroupWithDistinguishedName(DistinguishedName); SetValue(group); return group; @@ -91,7 +88,7 @@ namespace Disco.BI.Interop.ActiveDirectory if (groupRecord == null) { // Load from AD - var group = ActiveDirectory.GetGroupFromSecurityIdentifier(SecurityIdentifier); + var group = ActiveDirectory.RetrieveGroupWithSecurityIdentifier(SecurityIdentifier); SetValue(group); return group; diff --git a/Disco.Services/Interop/ActiveDirectory/Internal/ADInterop.cs b/Disco.Services/Interop/ActiveDirectory/Internal/ADInterop.cs new file mode 100644 index 00000000..60fc8016 --- /dev/null +++ b/Disco.Services/Interop/ActiveDirectory/Internal/ADInterop.cs @@ -0,0 +1,617 @@ +using Disco.Data.Repository; +using Disco.Models.Interop.ActiveDirectory; +using Disco.Services.Tasks; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; +using System.Security.Principal; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Services.Interop.ActiveDirectory.Internal +{ + internal static class ADInterop + { + public static List Domains { get; private set; } + public static ActiveDirectoryDomain PrimaryDomain { get; private set; } + public static ActiveDirectorySite Site { get; private set; } + internal static List _ForestServers { get; set; } + private static bool _SearchEntireForest { get; set; } + private static bool _Initialized = false; + private static object _InitializeLock = new object(); + + #region Initialization + + public static void Initialize(DiscoDataContext Database) + { + if (!_Initialized) + { + lock (_InitializeLock) + { + if (!_Initialized) + { + _SearchEntireForest = Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest ?? true; // Default True + + using (var computerDomain = Domain.GetComputerDomain()) + { + PrimaryDomain = GetDomainInternal(computerDomain, Database); + + Domains = computerDomain.Forest.Domains.Cast().Select(d => + { + if (d.Name == PrimaryDomain.DnsName) + return PrimaryDomain; + else + return GetDomainInternal(d, Database); + }).ToList(); + } + + Site = ActiveDirectorySite.GetComputerSite(); + } + } + } + } + + private static ActiveDirectoryDomain GetDomainInternal(Domain d, DiscoDataContext Database) + { + string ldapPath = string.Format("LDAP://{0}/", d.Name); + string defaultNamingContext; + string configurationNamingContext; + string netBiosName; + + using (var adRootDSE = new DirectoryEntry(ldapPath + "RootDSE")) + { + defaultNamingContext = adRootDSE.Properties["defaultNamingContext"][0].ToString(); + configurationNamingContext = adRootDSE.Properties["configurationNamingContext"][0].ToString(); + } + + using (var configSearchRoot = new DirectoryEntry(ldapPath + "CN=Partitions," + configurationNamingContext)) + { + var configSearchFilter = string.Format("(&(objectcategory=Crossref)(dnsRoot={0})(netBIOSName=*))", d.Name); + var configSearchLoadProperites = new string[] { "NetBIOSName" }; + + using (var configSearcher = new DirectorySearcher(configSearchRoot, configSearchFilter, configSearchLoadProperites, System.DirectoryServices.SearchScope.OneLevel)) + { + SearchResult configResult = configSearcher.FindOne(); + + if (configResult != null) + netBiosName = configResult.Properties["NetBIOSName"][0].ToString(); + else + netBiosName = null; + } + } + + // Search Containers + List searchContainersAll = Database.DiscoConfiguration.ActiveDirectory.SearchContainers; + List searchContainers = null; + + if (searchContainersAll != null && searchContainersAll.Count > 0) + searchContainers = Database.DiscoConfiguration.ActiveDirectory.SearchContainers.Where(c => c.EndsWith(defaultNamingContext, StringComparison.InvariantCultureIgnoreCase)).ToList(); + else + searchContainers = new List() { defaultNamingContext }; // No search constraints set - search entire tree + + return new ActiveDirectoryDomain(d.Name, netBiosName, defaultNamingContext, searchContainers); + } + + public static void UpdateSearchContainers(DiscoDataContext Database, IEnumerable Containers) + { + if (Containers != null) + { + var distinctContainers = Containers + .Where(c => !string.IsNullOrWhiteSpace(c)) + .Distinct().ToList(); + + Containers = distinctContainers.Where(c => !distinctContainers.Any(s => (c != s) && (c.EndsWith(s)))); + } + + if (Containers == null || Containers.Count() == 0) + { + Database.DiscoConfiguration.ActiveDirectory.SearchContainers = null; + + // No search constraints set - search entire tree + Domains.ForEach(d => d.UpdateSearchContainers(new string[] { d.DistinguishedName })); + } + else + { + Database.DiscoConfiguration.ActiveDirectory.SearchContainers = Containers.ToList(); + + Domains.ForEach(d => { d.UpdateSearchContainers(Containers.Where(c => c.EndsWith(d.DistinguishedName, StringComparison.InvariantCultureIgnoreCase))); }); + } + } + + public static bool UpdateSearchEntireForest(DiscoDataContext Database, bool SearchEntireForest) + { + if (SearchEntireForest == false) + { + Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false; + ADInterop._SearchEntireForest = false; + return true; + } + else + { + var forestServers = LoadForestServers(); + if (forestServers.Count <= ActiveDirectory.MaxForestServerSearch) + { + Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = true; + ADInterop._SearchEntireForest = true; + return true; + } + else + { + Database.DiscoConfiguration.ActiveDirectory.SearchEntireForest = false; + ADInterop._SearchEntireForest = false; + return false; + } + } + } + + #endregion + + #region Domain Getters + + public static bool TryGetDomainByDistinguishedName(string DistinguishedName, out ActiveDirectoryDomain Domain) + { + // Find closest match + Domain = ADInterop.Domains.Where(d => DistinguishedName.EndsWith(d.DistinguishedName, StringComparison.InvariantCultureIgnoreCase)) + .OrderByDescending(d => d.DistinguishedName.Length).FirstOrDefault(); + + return (Domain != null); + } + public static ActiveDirectoryDomain GetDomainByDistinguishedName(string DistinguishedName) + { + ActiveDirectoryDomain domain; + if (!TryGetDomainByDistinguishedName(DistinguishedName, out domain)) + throw new ArgumentException(string.Format("The domain is unknown distinguished name: [{0}]", DistinguishedName), "Id"); + return domain; + } + + public static bool TryGetDomainByNetBiosName(string NetBiosName, out ActiveDirectoryDomain Domain) + { + Domain = ADInterop.Domains.FirstOrDefault(d => d.NetBiosName.Equals(NetBiosName, StringComparison.InvariantCultureIgnoreCase)); + return (Domain != null); + } + public static ActiveDirectoryDomain GetDomainByNetBiosName(string NetBiosName) + { + ActiveDirectoryDomain domain; + if (!TryGetDomainByNetBiosName(NetBiosName, out domain)) + throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", NetBiosName), "Id"); + return domain; + } + + public static bool TryGetDomainByDnsName(string DnsName, out ActiveDirectoryDomain Domain) + { + Domain = ADInterop.Domains.FirstOrDefault(d => d.DnsName.Equals(DnsName, StringComparison.InvariantCultureIgnoreCase)); + return (Domain != null); + } + public static ActiveDirectoryDomain GetDomainByDnsName(string DnsName) + { + ActiveDirectoryDomain domain; + if (!TryGetDomainByDnsName(DnsName, out domain)) + throw new ArgumentException(string.Format("The specified domain is unknown [{0}]", DnsName), "Id"); + return domain; + } + + public static bool TryGetDomainFromId(string Id, out ActiveDirectoryDomain Domain) + { + if (string.IsNullOrWhiteSpace(Id)) + throw new ArgumentNullException("Id"); + + var idSplit = UserExtensions.SplitUserId(Id); + + if (idSplit.Item1 == null) + throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id"); + + if (string.IsNullOrWhiteSpace(idSplit.Item1)) + throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id"); + if (string.IsNullOrWhiteSpace(idSplit.Item2)) + throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id"); + + return TryGetDomainByNetBiosName(idSplit.Item1, out Domain); + } + public static ActiveDirectoryDomain GetDomainFromId(string Id) + { + if (string.IsNullOrWhiteSpace(Id)) + throw new ArgumentNullException("Id"); + + var idSplit = UserExtensions.SplitUserId(Id); + + if (idSplit.Item1 == null) + throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id"); + + if (string.IsNullOrWhiteSpace(idSplit.Item1)) + throw new ArgumentException(string.Format("The Id Domain was empty [{0}]", Id), "Id"); + if (string.IsNullOrWhiteSpace(idSplit.Item2)) + throw new ArgumentException(string.Format("The Id Name was empty [{0}]", Id), "Id"); + + return GetDomainByNetBiosName(idSplit.Item1); + } + + public static List LoadForestServers() + { + if (_ForestServers == null) + { + lock (_InitializeLock) + { + if (_ForestServers == null) + { + var status = ADDiscoverForestServers.ScheduleNow(); + status.CompletionTask.Wait(); + } + } + } + return _ForestServers; + } + public static Task> LoadForestServersAsync() + { + if (_ForestServers != null) + return Task.FromResult(_ForestServers); + + lock (_InitializeLock) + { + if (_ForestServers != null) + return Task.FromResult(_ForestServers); + + // Invoke Scheduled Task + var status = ADDiscoverForestServers.ScheduleNow(); + + return status.CompletionTask.ContinueWith(t => + { + return ADInterop._ForestServers.ToList(); + }); + } + } + + public static bool SearchEntireForest + { + get + { + if (_ForestServers != null && _ForestServers.Count > ActiveDirectory.MaxForestServerSearch) + return false; // Never + + return _SearchEntireForest; + } + } + + #endregion + + #region Searching + + public static IEnumerable SearchAll(string LdapFilter, string[] LoadProperties) + { + return SearchAll(Domains, LdapFilter, LoadProperties); + } + public static IEnumerable SearchAll(string LdapFilter, int ResultLimit, string[] LoadProperties) + { + return SearchAll(Domains, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchAll(IEnumerable> DomainsWithController, string LdapFilter, string[] LoadProperties) + { + return SearchAll(DomainsWithController, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchAll(IEnumerable Domains, string LdapFilter, string[] LoadProperties) + { + return SearchAll(Domains, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties) + { + return SearchAll(Domain, DomainController, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties) + { + return SearchAll(Domain, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchAll(IEnumerable> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + var query = DomainsWithController + .SelectMany(d => SearchAll(d.Item1, d.Item2, LdapFilter, ResultLimit, LoadProperties)); + + if (ResultLimit.HasValue) + query = query.Take(ResultLimit.Value); + + return query.ToList(); + } + public static IEnumerable SearchAll(IEnumerable Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + var query = Domains + .SelectMany(domain => SearchAll(domain, LdapFilter, ResultLimit, LoadProperties)); + + if (ResultLimit.HasValue) + query = query.Take(ResultLimit.Value); + + return query.ToList(); + } + public static IEnumerable SearchAll(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + return SearchDomain(Domain, DomainController, null, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchAll(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + return SearchDomain(Domain, null, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchScope(string LdapFilter, string[] LoadProperties) + { + return SearchScope(Domains, LdapFilter, LoadProperties); + } + public static IEnumerable SearchScope(string LdapFilter, int ResultLimit, string[] LoadProperties) + { + return SearchScope(Domains, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchScope(IEnumerable Domains, string LdapFilter, string[] LoadProperties) + { + return SearchScope(Domains, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchScope(IEnumerable> DomainsWithController, string LdapFilter, string[] LoadProperties) + { + return SearchScope(DomainsWithController, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, string[] LoadProperties) + { + return SearchScope(Domain, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, string[] LoadProperties) + { + return SearchScope(Domain, DomainController, LdapFilter, null, LoadProperties); + } + public static IEnumerable SearchScope(IEnumerable> DomainsWithController, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + var query = DomainsWithController + .SelectMany(d => SearchScope(d.Item1, d.Item2, LdapFilter, ResultLimit, LoadProperties)); + + if (ResultLimit.HasValue) + query = query.Take(ResultLimit.Value); + + return query.ToList(); + } + public static IEnumerable SearchScope(IEnumerable Domains, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + var query = Domains + .SelectMany(domain => SearchScope(domain, LdapFilter, ResultLimit, LoadProperties)); + + if (ResultLimit.HasValue) + query = query.Take(ResultLimit.Value); + + return query.ToList(); + } + public static IEnumerable SearchScope(ActiveDirectoryDomain Domain, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + return SearchScope(Domain, null, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchScope(ActiveDirectoryDomain Domain, DomainController DomainController, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + if (Domain.SearchContainers == null) + return Enumerable.Empty(); + + var query = Domain.SearchContainers + .SelectMany(container => SearchDomain(Domain, DomainController, container, LdapFilter, ResultLimit, LoadProperties)); + + if (ResultLimit.HasValue) + query = query.Take(ResultLimit.Value); + + return query.ToList(); + } + + public static IEnumerable SearchDomain(ActiveDirectoryDomain Domain, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + return SearchDomain(Domain, null, SearchRoot, LdapFilter, ResultLimit, LoadProperties); + } + public static IEnumerable SearchDomain(ActiveDirectoryDomain Domain, DomainController DomainController, string SearchRoot, string LdapFilter, int? ResultLimit, string[] LoadProperties) + { + string ldapServer = DomainController == null ? Domain.DnsName : DomainController.Name; + string searchRoot = SearchRoot ?? Domain.DistinguishedName; + string ldapPath = string.Format(@"LDAP://{0}/{1}", ldapServer, searchRoot); + + using (DirectoryEntry rootEntry = new DirectoryEntry(ldapPath)) + { + using (DirectorySearcher searcher = new DirectorySearcher(rootEntry, LdapFilter, LoadProperties, System.DirectoryServices.SearchScope.Subtree)) + { + searcher.PageSize = 500; + + if (ResultLimit.HasValue) + searcher.SizeLimit = ResultLimit.Value; + return searcher.FindAll().Cast().Select(result => new ActiveDirectorySearchResult() + { + Domain = Domain, + SearchRoot = searchRoot, + Result = result, + }); + } + } + } + + #endregion + + public static string OfflineDomainJoinProvision(ActiveDirectoryDomain Domain, DomainController DomainController, string ComputerSamAccountName, string OrganisationalUnit, out string DiagnosticInformation) + { + StringBuilder diagnosticInfo = new StringBuilder(); + string DJoinResult = null; + + if (!string.IsNullOrWhiteSpace(ComputerSamAccountName)) + ComputerSamAccountName = ComputerSamAccountName.TrimEnd('$'); + if (string.IsNullOrWhiteSpace(ComputerSamAccountName) || ComputerSamAccountName.Length > 24) + throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName"); + + // Ensure Specified OU Exists + if (!string.IsNullOrEmpty(OrganisationalUnit)) + { + try + { + using (var deOU = DomainController.RetrieveDirectoryEntry(OrganisationalUnit)) + { + if (deOU == null) + throw new Exception(string.Format("OU's Directory Entry couldn't be found at [{0}]", OrganisationalUnit)); + } + } + catch (Exception ex) + { + throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", OrganisationalUnit), "OrganisationalUnit", ex); + } + } + + string tempFileName = System.IO.Path.GetTempFileName(); + string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0}\"", OrganisationalUnit) : string.Empty; + string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"", + Domain.DnsName, + DomainController.Name, + ComputerSamAccountName, + argumentOU, + tempFileName + ); + ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments) + { + CreateNoWindow = true, + ErrorDialog = false, + LoadUserProfile = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false + }; + diagnosticInfo.AppendFormat("{0} {1}", "DJOIN.EXE", arguments); + diagnosticInfo.AppendLine(); + + string stdOutput; + string stdError; + using (Process commandProc = Process.Start(commandStarter)) + { + commandProc.WaitForExit(20000); + stdOutput = commandProc.StandardOutput.ReadToEnd(); + stdError = commandProc.StandardError.ReadToEnd(); + } + if (!string.IsNullOrWhiteSpace(stdOutput)) + diagnosticInfo.AppendLine(stdOutput); + if (!string.IsNullOrWhiteSpace(stdError)) + diagnosticInfo.AppendLine(stdError); + + 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)); + + DiagnosticInformation = diagnosticInfo.ToString(); + + return DJoinResult; + } + + public static DirectoryEntry RetrieveDirectoryEntry(string DistinguishedName, out ActiveDirectoryDomain Domain) + { + if (string.IsNullOrWhiteSpace(DistinguishedName)) + throw new ArgumentNullException("DistinguishedName"); + + // Find Domain + var domain = GetDomainByDistinguishedName(DistinguishedName); + + Domain = domain; + + return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", domain.DnsName, DistinguishedName)); + } + + public static DomainController RetrieveWritableDomainController(this ActiveDirectoryDomain domain) + { + var adContext = new DirectoryContext(DirectoryContextType.Domain, domain.DnsName); + using (var adDomain = Domain.GetDomain(adContext)) + { + return adDomain.FindDomainController(LocatorOptions.WriteableRequired); + } + } + + public static DirectoryEntry RetrieveDirectoryEntry(this DomainController domainController, string DistinguishedName) + { + return new DirectoryEntry(string.Format(@"LDAP://{0}/{1}", domainController.Name, DistinguishedName)); + } + + public static void DeleteObjectRecursive(this DirectoryEntry directoryEntry) + { + DeleteObjectRecursiveInternal(directoryEntry); + + using (var deParent = directoryEntry.Parent) + { + deParent.Children.Remove(directoryEntry); + } + } + private static void DeleteObjectRecursiveInternal(DirectoryEntry directoryEntry) + { + List children = directoryEntry.Children.Cast().ToList(); + + foreach (var child in children) + { + DeleteObjectRecursive(child); + directoryEntry.Children.Remove(child); + child.Dispose(); + } + } + + #region Helpers + + 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(); + } + } + + #endregion + } +} diff --git a/Disco.Services/Interop/ActiveDirectory/Internal/ADUpdateLastNetworkLogonDateJob.cs b/Disco.Services/Interop/ActiveDirectory/Internal/ADUpdateLastNetworkLogonDateJob.cs new file mode 100644 index 00000000..3703653a --- /dev/null +++ b/Disco.Services/Interop/ActiveDirectory/Internal/ADUpdateLastNetworkLogonDateJob.cs @@ -0,0 +1,231 @@ +using Disco.Data.Repository; +using Disco.Models.Interop.ActiveDirectory; +using Disco.Models.Repository; +using Disco.Services.Logging; +using Disco.Services.Tasks; +using Quartz; +using System; +using System.Collections; +using System.Collections.Generic; +using System.DirectoryServices; +using System.DirectoryServices.ActiveDirectory; +using System.Linq; + +namespace Disco.Services.Interop.ActiveDirectory.Internal +{ + public class ADUpdateLastNetworkLogonDateJob : 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(ADUpdateLastNetworkLogonDateJob)).Where(s => s.IsRunning).FirstOrDefault(); + if (existingTask != null) + return existingTask; + + var instance = new ADUpdateLastNetworkLogonDateJob(); + return instance.ScheduleTask(); + } + + public static bool UpdateLastNetworkLogonDate(Device Device) + { + const string ldapFilterTemplate = "(&(objectCategory=Computer)(sAMAccountName={0}))"; + string[] ldapProperties = new string[] { "lastLogon", "lastLogonTimestamp" }; + + System.DateTime? lastLogon = null; + + if (!string.IsNullOrEmpty(Device.DeviceDomainId)) + { + var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$"; + var ldapFilter = string.Format(ldapFilterTemplate, ADInterop.EscapeLdapQuery(deviceSamAccountName)); + + var domain = ADInterop.GetDomainFromId(Device.DeviceDomainId); + IEnumerable domainControllers; + + if (ADInterop.SearchEntireForest) + domainControllers = domain.RetrieveReachableDomainControllers(); + else + domainControllers = ADInterop.Site.RetrieveReachableDomainControllers(domain); + + lastLogon = domainControllers.Select(dc => + { + using (var directoryRoot = dc.RetrieveDirectoryEntry(domain.DistinguishedName)) + { + using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree)) + { + var directoryResult = directorySearcher.FindOne(); + + if (directoryResult != null) + { + long lastLogonValue = default(long); + long lastLogonTimestampValue = default(long); + + var lastLogonProperty = directoryResult.Properties["lastLogon"]; + if (lastLogonProperty != null && lastLogonProperty.Count > 0) + lastLogonValue = (long)lastLogonProperty[0]; + var lastLogonTimestampProperty = directoryResult.Properties["lastLogonTimestamp"]; + if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0) + lastLogonTimestampValue = (long)lastLogonTimestampProperty[0]; + + long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue); + + if (highedValue > 0) + return (DateTime?)new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L); + else + return null; + } + } + } + return null; + }).Where(dt => dt.HasValue).Max(); + } + + if (lastLogon.HasValue && + ( + !Device.LastNetworkLogonDate.HasValue + || Device.LastNetworkLogonDate.Value < lastLogon + )) + { + Device.LastNetworkLogonDate = lastLogon; + return true; + } + return false; + } + + private static void UpdateLastNetworkLogonDates(DiscoDataContext Database, ScheduledTaskStatus status) + { + const string ldapFilter = "(objectCategory=Computer)"; + string[] ldapProperties = new string[] { "sAMAccountName", "lastLogon" }; + + status.UpdateStatus(2, "Initializing", "Determining Domains and Available Domain Controllers"); + + // Determine Domain Controllers to Query + IEnumerable> domainControllers; + if (ADInterop.SearchEntireForest) + domainControllers = ADInterop.Domains.SelectMany(d => d.RetrieveReachableDomainControllers(), (d, dc) => Tuple.Create(d, dc)); + else + domainControllers = ADInterop.Domains.SelectMany(d => ADInterop.Site.RetrieveReachableDomainControllers(d), (d, dc) => Tuple.Create(d, dc)); + + // Determine Queries + var requiredRueries = domainControllers + .Where(s => s.Item1.SearchContainers != null && s.Item1.SearchContainers.Count > 0) + .SelectMany(s => s.Item1.SearchContainers, (s, c) => Tuple.Create(s.Item1, s.Item2, c)).ToList(); + + var queries = Enumerable.Range(0, requiredRueries.Count).Select(i => + { + var q = requiredRueries[i]; + return Tuple.Create(i, q.Item1, q.Item2, q.Item3); + }); + + var queryResults = queries.SelectMany(q => + { + var queryIndex = q.Item1; + var domain = q.Item2; + var domainController = q.Item3; + var searchRoot = q.Item4; + + // Update Status + double progress = 5 + (queryIndex * (90 / requiredRueries.Count)); + status.UpdateStatus(progress, string.Format("Querying Domain [{0}] using controller [{1}]", domain.NetBiosName, domainController.Name), string.Format("Searching: {0}", searchRoot)); + + // Perform Query + using (var directoryRoot = domainController.RetrieveDirectoryEntry(searchRoot)) + { + using (var directorySearcher = new DirectorySearcher(directoryRoot, ldapFilter, ldapProperties, SearchScope.Subtree)) + { + directorySearcher.PageSize = 500; + + var directoryResults = directorySearcher.FindAll(); + + if (directoryResults != null) + { + return directoryResults.Cast().Select(result => + { + var samAccountProperity = result.Properties["sAMAccountName"]; + + + long lastLogonValue = default(long); + long lastLogonTimestampValue = default(long); + + var lastLogonProperty = result.Properties["lastLogon"]; + if (lastLogonProperty != null && lastLogonProperty.Count > 0) + lastLogonValue = (long)lastLogonProperty[0]; + var lastLogonTimestampProperty = result.Properties["lastLogonTimestamp"]; + if (lastLogonTimestampProperty != null && lastLogonTimestampProperty.Count > 0) + lastLogonTimestampValue = (long)lastLogonTimestampProperty[0]; + + long highedValue = Math.Max(lastLogonValue, lastLogonTimestampValue); + + if (highedValue > 0) + { + var computerName = string.Format(@"{0}\{1}", domain.NetBiosName, samAccountProperity[0].ToString().TrimEnd('$')); + var lastLogon = new DateTime((DateTime.FromFileTime(highedValue).Ticks / 10000000L) * 10000000L); + return Tuple.Create(computerName, lastLogon); + } + else + return null; + }).Where(i => i != null).ToList(); + } + else + { + return Enumerable.Empty>(); + } + } + } + }).GroupBy(r => r.Item1, StringComparer.InvariantCultureIgnoreCase).ToDictionary(g => g.Key.ToUpper(), g => g.Max(i => i.Item2)); + + status.UpdateStatus(90, "Processing Results", "Processing last network logon dates and looking for updates"); + + foreach (Device device in Database.Devices.Where(device => device.DeviceDomainId != null)) + { + DateTime lastLogonDate; + if (queryResults.TryGetValue(device.DeviceDomainId.ToUpper(), out lastLogonDate)) + { + if (!device.LastNetworkLogonDate.HasValue) + device.LastNetworkLogonDate = lastLogonDate; + else + { + // Change accuracy to the second + lastLogonDate = new DateTime((lastLogonDate.Ticks / 10000000L) * 10000000L); + + if (device.LastNetworkLogonDate.Value < lastLogonDate) + device.LastNetworkLogonDate = lastLogonDate; + } + } + } + } + + } +} diff --git a/Disco.Services/Jobs/JobExtensions.cs b/Disco.Services/Jobs/JobExtensions.cs index dd1600f5..9455e5f5 100644 --- a/Disco.Services/Jobs/JobExtensions.cs +++ b/Disco.Services/Jobs/JobExtensions.cs @@ -1,5 +1,6 @@ using Disco.Models.Repository; using Disco.Models.Services.Jobs.JobLists; +using Disco.Services.Interop.ActiveDirectory; using System; using System.Collections.Generic; using System.Linq; @@ -61,10 +62,13 @@ namespace Disco.Services { i.UserId = j.UserId; i.UserDisplayName = j.User.DisplayName; + + i.UserFriendlyId = UserExtensions.FriendlyUserId(j.UserId); } if (j.OpenedTechUser != null) { i.OpenedTechUserId = j.OpenedTechUserId; + i.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId); i.OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName; } diff --git a/Disco.Services/Jobs/JobLists/JobTableExtensions.cs b/Disco.Services/Jobs/JobLists/JobTableExtensions.cs index 9625cd6e..7634ab50 100644 --- a/Disco.Services/Jobs/JobLists/JobTableExtensions.cs +++ b/Disco.Services/Jobs/JobLists/JobTableExtensions.cs @@ -232,8 +232,13 @@ namespace Disco.Services model.ShowDeviceAddress = Database.DiscoConfiguration.MultiSiteMode; foreach (var j in items) + { + j.UserFriendlyId =j.UserId == null ? null : UserExtensions.FriendlyUserId(j.UserId); + j.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId); + if (j.DeviceAddressId.HasValue) j.DeviceAddress = Database.DiscoConfiguration.OrganisationAddresses.GetAddress(j.DeviceAddressId.Value).Name; + } return items; } diff --git a/Disco.Services/Jobs/JobQueues/JobQueueService.cs b/Disco.Services/Jobs/JobQueues/JobQueueService.cs index 6d097a56..bef9f9d4 100644 --- a/Disco.Services/Jobs/JobQueues/JobQueueService.cs +++ b/Disco.Services/Jobs/JobQueues/JobQueueService.cs @@ -131,7 +131,7 @@ namespace Disco.Services.Jobs.JobQueues public static ReadOnlyCollection UsersQueues(User User) { - return UsersQueues(User.Id); + return UsersQueues(User.UserId); } public static ReadOnlyCollection UsersQueues(string UserId) { @@ -141,7 +141,7 @@ namespace Disco.Services.Jobs.JobQueues } public static ReadOnlyCollection UsersQueues(AuthorizationToken UserAuthorization) { - string cacheKey = string.Format(_cacheHttpRequestKey, UserAuthorization.User.Id); + string cacheKey = string.Format(_cacheHttpRequestKey, UserAuthorization.User.UserId); ReadOnlyCollection tokens = null; // Check for ASP.NET @@ -152,7 +152,7 @@ namespace Disco.Services.Jobs.JobQueues if (tokens == null) { - var subjectIds = (new string[] { UserAuthorization.User.Id }).Concat(UserAuthorization.GroupMembership); + var subjectIds = (new string[] { UserAuthorization.User.UserId }).Concat(UserAuthorization.GroupMembership); tokens = _cache.GetQueuesForSubject(subjectIds); HttpContext.Current.Items[_cacheHttpRequestKey] = tokens; diff --git a/Disco.Services/Plugins/PluginWebHandlerController.cs b/Disco.Services/Plugins/PluginWebHandlerController.cs index 5c6f1854..be797df1 100644 --- a/Disco.Services/Plugins/PluginWebHandlerController.cs +++ b/Disco.Services/Plugins/PluginWebHandlerController.cs @@ -30,7 +30,7 @@ namespace Disco.Services.Plugins var resource = string.Format("{0} [{1}]", attributeDenied.AuthorizeResource, HostController.Request.RawUrl); if (CurrentUser != null) - AuthorizationLog.LogAccessDenied(CurrentUser.Id, resource, message); + AuthorizationLog.LogAccessDenied(CurrentUser.UserId, resource, message); return new HttpUnauthorizedResult(); } diff --git a/Disco.Services/Searching/Search.cs b/Disco.Services/Searching/Search.cs index 3149e810..f88a02be 100644 --- a/Disco.Services/Searching/Search.cs +++ b/Disco.Services/Searching/Search.cs @@ -3,6 +3,7 @@ using Disco.Models.Interop.ActiveDirectory; using Disco.Models.Repository; using Disco.Models.Services.Jobs.JobLists; using Disco.Models.Services.Searching; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Users; using System; using System.Collections.Generic; @@ -29,7 +30,7 @@ namespace Disco.Services.Searching j.Id == termInt || j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.DisplayName.Contains(Term)); } else @@ -37,7 +38,7 @@ namespace Disco.Services.Searching query = Database.Jobs.Where(j => j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.DisplayName.Contains(Term)); } @@ -75,7 +76,7 @@ namespace Disco.Services.Searching j.DeviceHeldLocation.Contains(Term) || j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.Surname.Contains(Term) || j.User.GivenName.Contains(Term) || j.User.DisplayName.Contains(Term) || @@ -89,7 +90,7 @@ namespace Disco.Services.Searching j.DeviceHeldLocation.Contains(Term) || j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.Surname.Contains(Term) || j.User.GivenName.Contains(Term) || j.User.DisplayName.Contains(Term)); @@ -103,7 +104,7 @@ namespace Disco.Services.Searching j.DeviceHeldLocation.Contains(Term) || j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.Surname.Contains(Term) || j.User.GivenName.Contains(Term) || j.User.DisplayName.Contains(Term) || @@ -116,7 +117,7 @@ namespace Disco.Services.Searching j.DeviceHeldLocation.Contains(Term) || j.Device.SerialNumber.Contains(Term) || j.Device.AssetNumber.Contains(Term) || - j.User.Id == Term || + j.User.UserId == Term || j.User.Surname.Contains(Term) || j.User.GivenName.Contains(Term) || j.User.DisplayName.Contains(Term)); @@ -148,7 +149,7 @@ namespace Disco.Services.Searching UserService.SearchUsers(Database, Term); var matches = Database.Users.Where(u => - u.Id.Contains(Term) || + u.UserId.Contains(Term) || u.Surname.Contains(Term) || u.GivenName.Contains(Term) || u.DisplayName.Contains(Term) @@ -159,7 +160,7 @@ namespace Disco.Services.Searching return matches.Select(u => new UserSearchResultItem() { - Id = u.Id, + Id = u.UserId, Surname = u.Surname, GivenName = u.GivenName, DisplayName = u.DisplayName, @@ -170,7 +171,7 @@ namespace Disco.Services.Searching public static List SearchUsersUpstream(string Term, int? LimitCount = null) { - IEnumerable matches = UserService.SearchUsers(Term); + IEnumerable matches = ActiveDirectory.SearchUserAccounts(Term); if (LimitCount.HasValue) matches = matches.Take(LimitCount.Value); @@ -190,7 +191,7 @@ namespace Disco.Services.Searching { query = Database.Devices.Where(d => d.AssetNumber.Contains(Term) || - d.ComputerName.Contains(Term) || + d.DeviceDomainId.Contains(Term) || d.SerialNumber.Contains(Term) || d.Location.Contains(Term) || Term.Contains(d.SerialNumber) || @@ -201,7 +202,7 @@ namespace Disco.Services.Searching { query = Database.Devices.Where(d => d.AssetNumber.Contains(Term) || - d.ComputerName.Contains(Term) || + d.DeviceDomainId.Contains(Term) || d.SerialNumber.Contains(Term) || d.Location.Contains(Term) || Term.Contains(d.SerialNumber)); @@ -232,7 +233,7 @@ namespace Disco.Services.Searching { Id = d.SerialNumber, AssetNumber = d.AssetNumber, - ComputerName = d.ComputerName, + ComputerName = d.DeviceDomainId, DeviceModelDescription = d.DeviceModel.Description, DeviceProfileDescription = d.DeviceProfile.Description, DecommissionedDate = d.DecommissionedDate, diff --git a/Disco.Services/Tasks/ScheduledTaskStatus.cs b/Disco.Services/Tasks/ScheduledTaskStatus.cs index 792cae44..f0bf95e3 100644 --- a/Disco.Services/Tasks/ScheduledTaskStatus.cs +++ b/Disco.Services/Tasks/ScheduledTaskStatus.cs @@ -5,6 +5,7 @@ using System.Text; using Quartz; using System.Web.Script.Serialization; using System.Threading; +using System.Threading.Tasks; namespace Disco.Services.Tasks { @@ -16,7 +17,7 @@ namespace Disco.Services.Tasks private string _triggerKey; private string _taskName; private Type _taskType; - private EventWaitHandle _waitHandle; + private TaskCompletionSource _tcs; private bool _isSilent; private byte _progress; @@ -72,6 +73,14 @@ namespace Disco.Services.Tasks } } + public Task CompletionTask + { + get + { + return _tcs.Task; + } + } + #endregion #region Events @@ -87,7 +96,7 @@ namespace Disco.Services.Tasks { this._taskName = Task.TaskName; this._taskType = Task.GetType(); - this._waitHandle = new EventWaitHandle(false, EventResetMode.ManualReset); + this._tcs = new TaskCompletionSource(); this._sessionId = SessionId; this._triggerKey = TriggerKey; @@ -294,11 +303,13 @@ namespace Disco.Services.Tasks } internal void Finally() { - this._waitHandle.Set(); + this._tcs.SetResult(this); } public void Reset(DateTime? NextScheduledTimestamp) { - this._waitHandle.Reset(); + if (this._tcs != null) + this._tcs.Task.Dispose(); + this._tcs = new TaskCompletionSource(); List changedProperties = new List(); @@ -352,7 +363,7 @@ namespace Disco.Services.Tasks } public bool WaitUntilFinished(TimeSpan Timeout) { - return this._waitHandle.WaitOne(Timeout); + return this._tcs.Task.Wait(Timeout); } #endregion diff --git a/Disco.Services/Users/Searching.cs b/Disco.Services/Users/Searching.cs deleted file mode 100644 index bef5adbd..00000000 --- a/Disco.Services/Users/Searching.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Disco.Services.Users -{ - public static class Searching - { - - } -} diff --git a/Disco.Services/Users/UserExtensions.cs b/Disco.Services/Users/UserExtensions.cs new file mode 100644 index 00000000..f7bdc0ed --- /dev/null +++ b/Disco.Services/Users/UserExtensions.cs @@ -0,0 +1,42 @@ +using Disco.Models.Repository; +using Disco.Services.Interop.ActiveDirectory; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Disco.Services +{ + public static class UserExtensions + { + public static bool IsInPrimaryDomain(this User u) + { + return u.Domain.Equals(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase); + } + + public static string FriendlyId(this User u) + { + return FriendlyUserId(u.UserId); + } + + public static string FriendlyUserId(string UserId) + { + var splitUserId = SplitUserId(UserId); + + if (splitUserId.Item1 != null && splitUserId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase)) + return splitUserId.Item2; + else + return UserId; + } + + public static Tuple SplitUserId(string UserId) + { + var slashIndex = UserId.IndexOf('\\'); + if (slashIndex < 0) + return Tuple.Create(null, UserId); + else + return Tuple.Create(UserId.Substring(0, slashIndex), UserId.Substring(slashIndex + 1)); + } + } +} diff --git a/Disco.Services/Users/UserService.cs b/Disco.Services/Users/UserService.cs index c6d327dd..71f1dca1 100644 --- a/Disco.Services/Users/UserService.cs +++ b/Disco.Services/Users/UserService.cs @@ -3,6 +3,7 @@ using Disco.Models.Interop.ActiveDirectory; using Disco.Models.Repository; using Disco.Services.Authorization; using Disco.Services.Authorization.Roles; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Logging; using Newtonsoft.Json; using System; @@ -20,19 +21,9 @@ namespace Disco.Services.Users public static class UserService { private const string _cacheHttpRequestKey = "Disco_CurrentUserToken"; - private static Func _GetActiveDirectoryUserAccount; - private static Func _GetActiveDirectoryMachineAccount; - private static Func> _SearchActiveDirectoryUsers; - public static void Initialize(DiscoDataContext Database, - Func GetActiveDirectoryUserAccount, - Func GetActiveDirectoryMachineAccount, - Func> SearchActiveDirectoryUsers) + public static void Initialize(DiscoDataContext Database) { - _GetActiveDirectoryUserAccount = GetActiveDirectoryUserAccount; - _GetActiveDirectoryMachineAccount = GetActiveDirectoryMachineAccount; - _SearchActiveDirectoryUsers = SearchActiveDirectoryUsers; - Authorization.Roles.RoleCache.Initialize(Database); } @@ -56,10 +47,7 @@ namespace Disco.Services.Users userId = System.Security.Principal.WindowsIdentity.GetCurrent().Name; } - if (userId.Contains("\\")) - return userId.Substring(checked(userId.IndexOf("\\") + 1)); - else - return userId; + return userId; } } @@ -204,38 +192,31 @@ namespace Disco.Services.Users Cache.FlushCache(); } - internal static List SearchUsers(string Term) + internal static IEnumerable SearchUsers(DiscoDataContext Database, string Term) { - return _SearchActiveDirectoryUsers(Term); - } - - internal static List SearchUsers(DiscoDataContext Database, string Term) - { - var adImportedUsers = SearchUsers(Term); + var adImportedUsers = ActiveDirectory.SearchUserAccounts(Term); foreach (var adU in adImportedUsers.Select(adU => adU.ToRepositoryUser())) { - var existingUser = Database.Users.Find(adU.Id); + var existingUser = Database.Users.Find(adU.UserId); if (existingUser != null) existingUser.UpdateSelf(adU); else Database.Users.Add(adU); Database.SaveChanges(); - UserService.InvalidateCachedUser(adU.Id); + UserService.InvalidateCachedUser(adU.UserId); } return adImportedUsers; } internal static Tuple ImportUser(DiscoDataContext Database, string UserId) { - if (_GetActiveDirectoryUserAccount == null) - throw new InvalidOperationException("UserServer has not been Initialized"); if (string.IsNullOrEmpty(UserId)) throw new ArgumentNullException("UserId is required", "UserId"); if (UserId.EndsWith("$")) { // Machine Account - var adAccount = _GetActiveDirectoryMachineAccount(UserId, null); + var adAccount = ActiveDirectory.RetrieveMachineAccount(UserId); if (adAccount == null) return null; @@ -252,7 +233,7 @@ namespace Disco.Services.Users ActiveDirectoryUserAccount adAccount; try { - adAccount = _GetActiveDirectoryUserAccount(UserId, null); + adAccount = ActiveDirectory.RetrieveUserAccount(UserId); if (adAccount == null) throw new ArgumentException(string.Format("Invalid Username: '{0}'; User not found in Active Directory", UserId), "Username"); @@ -275,7 +256,7 @@ namespace Disco.Services.Users var user = adAccount.ToRepositoryUser(); // Update Repository - User existingUser = Database.Users.Find(user.Id); + User existingUser = Database.Users.Find(user.UserId); if (existingUser == null) Database.Users.Add(user); else diff --git a/Disco.Web/App_Code/AjaxHelpers.generated.cs b/Disco.Web/App_Code/AjaxHelpers.generated.cs index 9c7974a2..84c112f3 100644 --- a/Disco.Web/App_Code/AjaxHelpers.generated.cs +++ b/Disco.Web/App_Code/AjaxHelpers.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/App_Code/CommonHelpers.cshtml b/Disco.Web/App_Code/CommonHelpers.cshtml index 2c0d3189..5bfa79c0 100644 --- a/Disco.Web/App_Code/CommonHelpers.cshtml +++ b/Disco.Web/App_Code/CommonHelpers.cshtml @@ -2,11 +2,11 @@ @using Disco; @using Disco.BI.Extensions; @using Disco.Models.Repository; +@using Disco.Services; +@using Disco.Services.Web; @using Disco.Web; @using System.Web.Mvc @using System.Web.Mvc.Html; -@using Disco.Services.Web; - @helper FriendlyDate(DateTime d, string ElementId = null, bool WithoutSuffix = false) {@d.ToFullDateTime()} @@ -34,7 +34,7 @@ { if (u != null) { - @prepend @u.Id + @prepend @u.FriendlyId() } else { diff --git a/Disco.Web/App_Code/CommonHelpers.generated.cs b/Disco.Web/App_Code/CommonHelpers.generated.cs index 6eeaaae8..2b6798bd 100644 --- a/Disco.Web/App_Code/CommonHelpers.generated.cs +++ b/Disco.Web/App_Code/CommonHelpers.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -20,13 +20,13 @@ namespace Disco.Web using System.Web; using System.Web.Helpers; - #line 6 "..\..\App_Code\CommonHelpers.cshtml" + #line 8 "..\..\App_Code\CommonHelpers.cshtml" using System.Web.Mvc; #line default #line hidden - #line 7 "..\..\App_Code\CommonHelpers.cshtml" + #line 9 "..\..\App_Code\CommonHelpers.cshtml" using System.Web.Mvc.Html; #line default @@ -54,13 +54,19 @@ namespace Disco.Web #line default #line hidden - #line 8 "..\..\App_Code\CommonHelpers.cshtml" + #line 5 "..\..\App_Code\CommonHelpers.cshtml" + using Disco.Services; + + #line default + #line hidden + + #line 6 "..\..\App_Code\CommonHelpers.cshtml" using Disco.Services.Web; #line default #line hidden - #line 5 "..\..\App_Code\CommonHelpers.cshtml" + #line 7 "..\..\App_Code\CommonHelpers.cshtml" using Disco.Web; #line default @@ -509,7 +515,7 @@ WriteLiteralTo(@__razor_helper_writer, "\">"); #line 37 "..\..\App_Code\CommonHelpers.cshtml" -WriteTo(@__razor_helper_writer, u.Id); +WriteTo(@__razor_helper_writer, u.FriendlyId()); #line default #line hidden diff --git a/Disco.Web/App_Start/AppConfig.cs b/Disco.Web/App_Start/AppConfig.cs index 44bc53e9..8a8a62c4 100644 --- a/Disco.Web/App_Start/AppConfig.cs +++ b/Disco.Web/App_Start/AppConfig.cs @@ -1,10 +1,7 @@ -using System; -using System.Collections.Generic; +using Disco.Data.Repository; +using System; using System.Linq; using System.Web; -using Disco.Data.Repository; -using System.Threading; -using System.Reflection; namespace Disco.Web { @@ -32,6 +29,9 @@ namespace Disco.Web // Initialize Logging Disco.Services.Logging.LogContext.Initalize(Database, DiscoApplication.SchedulerFactory); + // Initialize Active Directory Interop + Disco.Services.Interop.ActiveDirectory.ActiveDirectory.Initialize(Database); + // Load Organisation Name DiscoApplication.OrganisationName = Database.DiscoConfiguration.OrganisationName; DiscoApplication.MultiSiteMode = Database.DiscoConfiguration.MultiSiteMode; @@ -43,11 +43,7 @@ namespace Disco.Web Database.DiscoConfiguration.ProxyPassword); // Initialize User Service Interop - Disco.Services.Users.UserService.Initialize(Database, - (UserId, AdditionalProperties) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetUserAccount(UserId, AdditionalProperties), - (UserId, AdditionalProperties) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetMachineAccount(UserId, null, null, AdditionalProperties), - (Term) => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(Term)); - + Disco.Services.Users.UserService.Initialize(Database); } public static void InitalizeNormalEnvironment(DiscoDataContext Database) diff --git a/Disco.Web/Areas/API/Controllers/AuthorizationRoleController.cs b/Disco.Web/Areas/API/Controllers/AuthorizationRoleController.cs index 08a3aaab..134c3e2b 100644 --- a/Disco.Web/Areas/API/Controllers/AuthorizationRoleController.cs +++ b/Disco.Web/Areas/API/Controllers/AuthorizationRoleController.cs @@ -1,9 +1,9 @@ using Disco.BI.Extensions; -using Disco.BI.Interop.ActiveDirectory; using Disco.Models.Interop.ActiveDirectory; using Disco.Models.Repository; using Disco.Services.Authorization; using Disco.Services.Authorization.Roles; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Users; using Disco.Services.Web; using System; @@ -75,7 +75,7 @@ namespace Disco.Web.Areas.API.Controllers var oldRoleName = AuthorizationRole.Name; AuthorizationRole.Name = Name; UserService.UpdateAuthorizationRole(Database, AuthorizationRole); - AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.Id, oldRoleName); + AuthorizationLog.LogRoleConfiguredRenamed(AuthorizationRole, CurrentUser.UserId, oldRoleName); } } } @@ -93,9 +93,9 @@ namespace Disco.Web.Areas.API.Controllers UserService.UpdateAuthorizationRole(Database, AuthorizationRole); if (removedClaims.Length > 0) - AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.Id, removedClaims); + AuthorizationLog.LogRoleConfiguredClaimsRemoved(AuthorizationRole, CurrentUser.UserId, removedClaims); if (addedClaims.Length > 0) - AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.Id, addedClaims); + AuthorizationLog.LogRoleConfiguredClaimsAdded(AuthorizationRole, CurrentUser.UserId, addedClaims); } private void UpdateSubjects(AuthorizationRole AuthorizationRole, string[] Subjects) @@ -107,7 +107,7 @@ namespace Disco.Web.Areas.API.Controllers // Validate Subjects if (Subjects != null && Subjects.Length > 0) { - var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple(s, ActiveDirectory.GetObject(s))).ToList(); + var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple(s, ActiveDirectory.RetrieveObject(s))).ToList(); var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList(); if (invalidSubjects.Count > 0) @@ -130,9 +130,9 @@ namespace Disco.Web.Areas.API.Controllers UserService.UpdateAuthorizationRole(Database, AuthorizationRole); if (removedSubjects != null && removedSubjects.Length > 0) - AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.Id, removedSubjects); + AuthorizationLog.LogRoleConfiguredSubjectsRemoved(AuthorizationRole, CurrentUser.UserId, removedSubjects); if (addedSubjects != null && addedSubjects.Length > 0) - AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.Id, addedSubjects); + AuthorizationLog.LogRoleConfiguredSubjectsAdded(AuthorizationRole, CurrentUser.UserId, addedSubjects); } } @@ -234,8 +234,8 @@ namespace Disco.Web.Areas.API.Controllers public virtual ActionResult SearchSubjects(string term) { - var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast(); - var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast(); + var groupResults = ActiveDirectory.SearchGroups(term).Cast(); + var userResults = ActiveDirectory.SearchUserAccounts(term).Cast(); var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName) .Select(r => Models.AuthorizationRole.SubjectItem.FromActiveDirectoryObject(r)).ToList(); @@ -245,7 +245,7 @@ namespace Disco.Web.Areas.API.Controllers public virtual ActionResult Subject(string Id) { - var subject = ActiveDirectory.GetObject(Id); + var subject = ActiveDirectory.RetrieveObject(Id); if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup)) return Json(null, JsonRequestBehavior.AllowGet); diff --git a/Disco.Web/Areas/API/Controllers/DeviceController.cs b/Disco.Web/Areas/API/Controllers/DeviceController.cs index 9938bff6..22bfc633 100644 --- a/Disco.Web/Areas/API/Controllers/DeviceController.cs +++ b/Disco.Web/Areas/API/Controllers/DeviceController.cs @@ -1,6 +1,6 @@ using Disco.BI.Extensions; -using Disco.BI.Interop.ActiveDirectory; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Users; using Disco.Services.Web; using System; @@ -148,9 +148,9 @@ namespace Disco.Web.Areas.API.Controllers device.DeviceProfile = p; // Update AD Account - if (!string.IsNullOrEmpty(device.ComputerName) && device.ComputerName.Length <= 24) + if (!string.IsNullOrEmpty(device.DeviceDomainId) && device.DeviceDomainId.Length <= 24) { - var adMachineAccount = ActiveDirectory.GetMachineAccount(device.ComputerName); + var adMachineAccount = ActiveDirectory.RetrieveMachineAccount(device.DeviceDomainId); if (adMachineAccount != null) adMachineAccount.SetDescription(device); } @@ -501,7 +501,7 @@ namespace Disco.Web.Areas.API.Controllers var da = Database.DeviceAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault(); if (da != null) { - if (da.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase)) + if (da.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase)) Authorization.RequireAny(Claims.Device.Actions.RemoveAnyAttachments, Claims.Device.Actions.RemoveOwnAttachments); else Authorization.Require(Claims.Device.Actions.RemoveAnyAttachments); diff --git a/Disco.Web/Areas/API/Controllers/DeviceProfileController.cs b/Disco.Web/Areas/API/Controllers/DeviceProfileController.cs index 9f2a210d..e73eab4b 100644 --- a/Disco.Web/Areas/API/Controllers/DeviceProfileController.cs +++ b/Disco.Web/Areas/API/Controllers/DeviceProfileController.cs @@ -1,6 +1,7 @@ using Disco.BI.Extensions; using Disco.Models.Repository; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Web; using System; using System.Linq; @@ -90,7 +91,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Device Profile Number"); } if (redirect.HasValue && redirect.Value) - return RedirectToAction(MVC.Config.DeviceModel.Index(deviceProfile.Id)); + return RedirectToAction(MVC.Config.DeviceProfile.Index(deviceProfile.Id)); else return Json("OK", JsonRequestBehavior.AllowGet); } @@ -245,11 +246,13 @@ namespace Disco.Web.Areas.API.Controllers private void UpdateOrganisationalUnit(Disco.Models.Repository.DeviceProfile deviceProfile, string OrganisationalUnit) { if (string.IsNullOrWhiteSpace(OrganisationalUnit)) - OrganisationalUnit = null; + OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer(); - deviceProfile.OrganisationalUnit = OrganisationalUnit; - - Database.SaveChanges(); + if (OrganisationalUnit != deviceProfile.OrganisationalUnit) + { + deviceProfile.OrganisationalUnit = OrganisationalUnit; + Database.SaveChanges(); + } } private void UpdateComputerNameTemplate(Disco.Models.Repository.DeviceProfile deviceProfile, string ComputerNameTemplate) @@ -364,13 +367,6 @@ namespace Disco.Web.Areas.API.Controllers } #endregion - [DiscoAuthorize(Claims.Config.DeviceProfile.Configure)] - public virtual ActionResult OrganisationalUnits() - { - var OUs = BI.Interop.ActiveDirectory.ActiveDirectory.GetOrganisationalUnitStructure(); - return Json(OUs, JsonRequestBehavior.AllowGet); - } - #region Actions [DiscoAuthorize(Claims.Config.DeviceProfile.Delete)] diff --git a/Disco.Web/Areas/API/Controllers/JobController.cs b/Disco.Web/Areas/API/Controllers/JobController.cs index 0cf0d06e..3d814914 100644 --- a/Disco.Web/Areas/API/Controllers/JobController.cs +++ b/Disco.Web/Areas/API/Controllers/JobController.cs @@ -663,7 +663,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.Id; + job.JobMetaNonWarranty.AccountingChargeRequiredUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -697,7 +697,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.Id; + job.JobMetaNonWarranty.AccountingChargeAddedUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -731,7 +731,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.Id; + job.JobMetaNonWarranty.AccountingChargePaidUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -765,7 +765,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.Id; + job.JobMetaNonWarranty.PurchaseOrderRaisedUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -808,7 +808,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.Id; + job.JobMetaNonWarranty.PurchaseOrderSentUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -842,7 +842,7 @@ namespace Disco.Web.Areas.API.Controllers throw new Exception("Invalid Date Format"); } } - job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.Id; + job.JobMetaNonWarranty.InvoiceReceivedUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -991,7 +991,7 @@ namespace Disco.Web.Areas.API.Controllers } } } - job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.Id; + job.JobMetaInsurance.ClaimFormSentUserId = CurrentUser.UserId; Database.SaveChanges(); return new Models.Job._DateChangeModel() { @@ -1508,7 +1508,7 @@ namespace Disco.Web.Areas.API.Controllers JobLog jobLog = new JobLog() { JobId = job.Id, - TechUserId = CurrentUser.Id, + TechUserId = CurrentUser.UserId, Timestamp = DateTime.Now, Comments = string.Format("Added Flag: {0}{1}Reason: {2}", flagStatus.Item1, Environment.NewLine, Reason) }; @@ -1857,7 +1857,7 @@ namespace Disco.Web.Areas.API.Controllers var jl = new Disco.Models.Repository.JobLog() { JobId = j.Id, - TechUserId = CurrentUser.Id, + TechUserId = CurrentUser.UserId, Timestamp = DateTime.Now, Comments = comment }; @@ -1876,7 +1876,7 @@ namespace Disco.Web.Areas.API.Controllers var jl = Database.JobLogs.Find(id); if (jl != null) { - if (jl.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase)) + if (jl.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase)) Authorization.RequireAny(Claims.Job.Actions.RemoveAnyLogs, Claims.Job.Actions.RemoveOwnLogs); else Authorization.Require(Claims.Job.Actions.RemoveAnyLogs); @@ -1950,7 +1950,7 @@ namespace Disco.Web.Areas.API.Controllers var ja = new Disco.Models.Repository.JobAttachment() { JobId = j.Id, - TechUserId = CurrentUser.Id, + TechUserId = CurrentUser.UserId, Filename = file.FileName, MimeType = contentType, Timestamp = DateTime.Now, @@ -2012,7 +2012,7 @@ namespace Disco.Web.Areas.API.Controllers var ja = Database.JobAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault(); if (ja != null) { - if (ja.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase)) + if (ja.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase)) Authorization.RequireAny(Claims.Job.Actions.RemoveAnyAttachments, Claims.Job.Actions.RemoveOwnAttachments); else Authorization.Require(Claims.Job.Actions.RemoveAnyAttachments); @@ -2046,7 +2046,7 @@ namespace Disco.Web.Areas.API.Controllers JobId = j.Id, Description = Description, Cost = cost, - TechUserId = CurrentUser.Id + TechUserId = CurrentUser.UserId }; Database.JobComponents.Add(jc); Database.SaveChanges(); diff --git a/Disco.Web/Areas/API/Controllers/JobQueueController.cs b/Disco.Web/Areas/API/Controllers/JobQueueController.cs index 3cd4ef01..239a5e78 100644 --- a/Disco.Web/Areas/API/Controllers/JobQueueController.cs +++ b/Disco.Web/Areas/API/Controllers/JobQueueController.cs @@ -1,5 +1,4 @@ -using Disco.BI.Interop.ActiveDirectory; -using Disco.Models.Interop.ActiveDirectory; +using Disco.Models.Interop.ActiveDirectory; using Disco.Models.Repository; using Disco.Services.Authorization; using Disco.Services.Jobs.JobQueues; @@ -9,6 +8,7 @@ using System; using System.Linq; using System.Web.Mvc; using System.Collections.Generic; +using Disco.Services.Interop.ActiveDirectory; namespace Disco.Web.Areas.API.Controllers { @@ -288,7 +288,7 @@ namespace Disco.Web.Areas.API.Controllers // Validate Subjects if (Subjects != null && Subjects.Length > 0) { - var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple(s, ActiveDirectory.GetObject(s))).ToList(); + var subjects = Subjects.Where(s => !string.IsNullOrWhiteSpace(s)).Select(s => s.Trim()).Select(s => new Tuple(s, ActiveDirectory.RetrieveObject(s))).ToList(); var invalidSubjects = subjects.Where(s => s.Item2 == null).ToList(); if (invalidSubjects.Count > 0) @@ -370,8 +370,8 @@ namespace Disco.Web.Areas.API.Controllers [DiscoAuthorize(Claims.Config.JobQueue.Configure)] public virtual ActionResult SearchSubjects(string term) { - var groupResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchGroups(term).Cast(); - var userResults = BI.Interop.ActiveDirectory.ActiveDirectory.SearchUsers(term).Cast(); + var groupResults = ActiveDirectory.SearchGroups(term).Cast(); + var userResults = ActiveDirectory.SearchUserAccounts(term).Cast(); var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName) .Select(r => Models.JobQueue.SubjectItem.FromActiveDirectoryObject(r)).ToList(); @@ -382,7 +382,7 @@ namespace Disco.Web.Areas.API.Controllers [DiscoAuthorize(Claims.Config.JobQueue.Configure)] public virtual ActionResult Subject(string Id) { - var subject = ActiveDirectory.GetObject(Id); + var subject = ActiveDirectory.RetrieveObject(Id); if (subject == null || !(subject is ActiveDirectoryUserAccount || subject is ActiveDirectoryGroup)) return Json(null, JsonRequestBehavior.AllowGet); diff --git a/Disco.Web/Areas/API/Controllers/SystemController.cs b/Disco.Web/Areas/API/Controllers/SystemController.cs index adf40523..bd92dc21 100644 --- a/Disco.Web/Areas/API/Controllers/SystemController.cs +++ b/Disco.Web/Areas/API/Controllers/SystemController.cs @@ -1,8 +1,11 @@ using Disco.BI.Extensions; -using Disco.BI.Interop.ActiveDirectory; +using Disco.Data.Configuration; +using Disco.Models.Interop.ActiveDirectory; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Web; using System; +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; @@ -17,7 +20,7 @@ namespace Disco.Web.Areas.API.Controllers [DiscoAuthorize(Claims.Config.System.Show)] public virtual ActionResult UpdateLastNetworkLogonDates() { - var taskStatus = ActiveDirectoryUpdateLastNetworkLogonDateJob.ScheduleImmediately(); + var taskStatus = Disco.Services.Interop.ActiveDirectory.Internal.ADUpdateLastNetworkLogonDateJob.ScheduleImmediately(); return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId)); } @@ -219,5 +222,97 @@ namespace Disco.Web.Areas.API.Controllers #endregion + #region Active Directory + + [DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)] + public virtual ActionResult UpdateActiveDirectorySearchScope(List Containers, bool redirect = false) + { + ActiveDirectory.UpdateSearchContainers(Database, Containers); + Database.SaveChanges(); + + if (redirect) + return RedirectToAction(MVC.Config.SystemConfig.Index()); + else + return Json("OK", JsonRequestBehavior.AllowGet); + } + + [DiscoAuthorize(Claims.Config.System.ConfigureActiveDirectory)] + public virtual ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect = false) + { + try + { + var result = ActiveDirectory.UpdateSearchEntireForest(Database, SearchEntireForest); + + Database.SaveChanges(); + + if (!result) + { + var forestServers = ActiveDirectory.LoadForestServers(); + if (forestServers.Count > ActiveDirectory.MaxForestServerSearch) + throw new InvalidOperationException(string.Format("This forest contains more than the Max Forest Server Search restriction ({0})", ActiveDirectory.MaxForestServerSearch)); + else + throw new InvalidOperationException("Unable to change the 'SearchEntireForest' property for an unknown reason, please report this bug"); + } + + if (redirect) + return RedirectToAction(MVC.Config.SystemConfig.Index()); + else + return Json("OK", JsonRequestBehavior.AllowGet); + } + catch (Exception ex) + { + if (redirect) + throw; + else + return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet); + } + } + + [DiscoAuthorizeAny(Claims.Config.System.ConfigureActiveDirectory, Claims.Config.DeviceProfile.Configure)] + public virtual ActionResult DomainOrganisationalUnits() + { + var domainOUs = ActiveDirectory.Domains + .Select(d => new Models.System.DomainOrganisationalUnitsModel() { Domain = d, OrganisationalUnits = ActiveDirectory.RetrieveOrganisationalUnitStructure(d) }) + .Select(ous => ous.ToFancyTreeNode()).ToList(); + + return Json(domainOUs, JsonRequestBehavior.AllowGet); + } + + #endregion + + #region Proxy Settings + + [DiscoAuthorize(Claims.Config.System.ConfigureProxy)] + public virtual ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect = false) + { + // Default Proxy Port + if (!ProxyPort.HasValue) + ProxyPort = 8080; + + SystemConfiguration config = Database.DiscoConfiguration; + //config.DataStoreLocation = DataStoreLocation; + config.ProxyAddress = ProxyAddress; + config.ProxyPort = ProxyPort.Value; + config.ProxyUsername = ProxyUsername; + config.ProxyPassword = ProxyPassword; + DiscoApplication.SetGlobalProxy(ProxyAddress, ProxyPort.Value, ProxyUsername, ProxyPassword); + + Database.SaveChanges(); + + // Try and check for updates if needed - After Proxy Changed + if (Database.DiscoConfiguration.UpdateLastCheck == null + || Database.DiscoConfiguration.UpdateLastCheck.ResponseTimestamp < DateTime.Now.AddDays(-1)) + { + Disco.BI.Interop.Community.UpdateCheckTask.ScheduleNow(); + } + + if (redirect) + return RedirectToAction(MVC.Config.SystemConfig.Index()); + else + return Json("OK", JsonRequestBehavior.AllowGet); + } + + #endregion + } } diff --git a/Disco.Web/Areas/API/Controllers/UserController.cs b/Disco.Web/Areas/API/Controllers/UserController.cs index fcf37c82..4c400c9a 100644 --- a/Disco.Web/Areas/API/Controllers/UserController.cs +++ b/Disco.Web/Areas/API/Controllers/UserController.cs @@ -1,5 +1,6 @@ using Disco.BI.Extensions; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Users; using Disco.Services.Web; using System; @@ -61,8 +62,13 @@ namespace Disco.Web.Areas.API.Controllers } [DiscoAuthorize(Claims.User.Actions.AddAttachments)] - public virtual ActionResult AttachmentUpload(string id, string Comments) + public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments) { + if (string.IsNullOrEmpty(Domain)) + id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id; + else + id = Domain + @"\" + id; + var u = Database.Users.Find(id); if (u != null) { @@ -77,7 +83,7 @@ namespace Disco.Web.Areas.API.Controllers var ua = new Disco.Models.Repository.UserAttachment() { - UserId = u.Id, + UserId = u.UserId, TechUserId = UserService.CurrentUserId, Filename = file.FileName, MimeType = contentType, @@ -118,9 +124,14 @@ namespace Disco.Web.Areas.API.Controllers } [DiscoAuthorize(Claims.User.ShowAttachments)] - public virtual ActionResult Attachments(string id) + public virtual ActionResult Attachments(string id, string Domain) { - var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.Id == id).FirstOrDefault(); + if (string.IsNullOrEmpty(Domain)) + id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id; + else + id = Domain + @"\" + id; + + var u = Database.Users.Include("UserAttachments.TechUser").Where(m => m.UserId == id).FirstOrDefault(); if (u != null) { var m = new Models.Attachment.AttachmentsModel() @@ -140,7 +151,7 @@ namespace Disco.Web.Areas.API.Controllers var ua = Database.UserAttachments.Include("TechUser").Where(m => m.Id == id).FirstOrDefault(); if (ua != null) { - if (ua.TechUserId.Equals(CurrentUser.Id, StringComparison.InvariantCultureIgnoreCase)) + if (ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.InvariantCultureIgnoreCase)) Authorization.RequireAny(Claims.User.Actions.RemoveAnyAttachments, Claims.User.Actions.RemoveOwnAttachments); else Authorization.Require(Claims.User.Actions.RemoveAnyAttachments); @@ -155,12 +166,18 @@ namespace Disco.Web.Areas.API.Controllers #endregion [DiscoAuthorize(Claims.User.Actions.GenerateDocuments)] - public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId) + public virtual ActionResult GeneratePdf(string id, string Domain, string DocumentTemplateId) { if (string.IsNullOrEmpty(id)) throw new ArgumentNullException("id"); if (string.IsNullOrEmpty(DocumentTemplateId)) throw new ArgumentNullException("AttachmentTypeId"); + + if (string.IsNullOrEmpty(Domain)) + id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id; + else + id = Domain + @"\" + id; + var user = Database.Users.Find(id); if (user != null) { @@ -174,7 +191,7 @@ namespace Disco.Web.Areas.API.Controllers pdf = documentTemplate.GeneratePdf(Database, user, UserService.CurrentUser, timeStamp, generationState); } Database.SaveChanges(); - return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.Id, timeStamp)); + return File(pdf, "application/pdf", string.Format("{0}_{1}_{2:yyyyMMdd-HHmmss}.pdf", documentTemplate.Id, user.UserId, timeStamp)); } else { diff --git a/Disco.Web/Areas/API/Models/System/DomainOrganisationalUnitsModel.cs b/Disco.Web/Areas/API/Models/System/DomainOrganisationalUnitsModel.cs new file mode 100644 index 00000000..c17b8aa2 --- /dev/null +++ b/Disco.Web/Areas/API/Models/System/DomainOrganisationalUnitsModel.cs @@ -0,0 +1,47 @@ +using Disco.Models.Interop.ActiveDirectory; +using Disco.Web.Models.Shared; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Disco.Web.Areas.API.Models.System +{ + public class DomainOrganisationalUnitsModel + { + public ActiveDirectoryDomain Domain { get; set; } + public List OrganisationalUnits { get; set; } + + public FancyTreeNode ToFancyTreeNode() + { + FancyTreeNode[] children = OrganisationalUnits.Select(ou => OrganisationalUnitToFancyTreeNode(ou)).ToArray(); + + return new FancyTreeNode() + { + key = Domain.DistinguishedName, + title = Domain.NetBiosName, + folder = true, + tooltip = Domain.DnsName, + children = children, + unselectable = false, + expanded = true + }; + } + private FancyTreeNode OrganisationalUnitToFancyTreeNode(ActiveDirectoryOrganisationalUnit OrganisationalUnit) + { + FancyTreeNode[] children = OrganisationalUnit.Children == null + ? null + : OrganisationalUnit.Children.Select(ou => OrganisationalUnitToFancyTreeNode(ou)).ToArray(); + + return new FancyTreeNode() + { + key = OrganisationalUnit.DistinguishedName, + title = OrganisationalUnit.Name, + folder = true, + tooltip = OrganisationalUnit.DistinguishedName, + children = children, + unselectable = false + }; + } + } +} \ No newline at end of file diff --git a/Disco.Web/Areas/Config/Controllers/AuthorizationRoleController.cs b/Disco.Web/Areas/Config/Controllers/AuthorizationRoleController.cs index 2c0eaa18..0726cc0c 100644 --- a/Disco.Web/Areas/Config/Controllers/AuthorizationRoleController.cs +++ b/Disco.Web/Areas/Config/Controllers/AuthorizationRoleController.cs @@ -2,6 +2,7 @@ using Disco.Models.UI.Config.AuthorizationRole; using Disco.Services.Authorization; using Disco.Services.Authorization.Roles; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Plugins.Features.UIExtension; using Disco.Services.Users; using Disco.Services.Web; @@ -27,7 +28,7 @@ namespace Disco.Web.Areas.Config.Controllers var token = RoleToken.FromAuthorizationRole(ar); var subjects = token.SubjectIds == null ? new List() : - token.SubjectIds.Select(subjectId => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetObject(subjectId)) + token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId)) .Where(item => item != null) .Select(item => Models.AuthorizationRole.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item)) .OrderBy(item => item.Name).ToList(); diff --git a/Disco.Web/Areas/Config/Controllers/DeviceProfileController.cs b/Disco.Web/Areas/Config/Controllers/DeviceProfileController.cs index 4516a92e..8ed208b0 100644 --- a/Disco.Web/Areas/Config/Controllers/DeviceProfileController.cs +++ b/Disco.Web/Areas/Config/Controllers/DeviceProfileController.cs @@ -2,6 +2,7 @@ using Disco.Models.Repository; using Disco.Models.UI.Config.DeviceProfile; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Plugins; using Disco.Services.Plugins.Features.CertificateProvider; using Disco.Services.Plugins.Features.UIExtension; @@ -75,7 +76,8 @@ namespace Disco.Web.Areas.Config.Controllers { ComputerNameTemplate = DeviceProfile.DefaultComputerNameTemplate, ProvisionADAccount = true, - DistributionType = DeviceProfile.DistributionTypes.OneToMany + DistributionType = DeviceProfile.DistributionTypes.OneToMany, + OrganisationalUnit = ActiveDirectory.PrimaryDomain.GetDefaultComputerContainer() } }; diff --git a/Disco.Web/Areas/Config/Controllers/JobQueueController.cs b/Disco.Web/Areas/Config/Controllers/JobQueueController.cs index c0b52f93..4be01521 100644 --- a/Disco.Web/Areas/Config/Controllers/JobQueueController.cs +++ b/Disco.Web/Areas/Config/Controllers/JobQueueController.cs @@ -2,6 +2,7 @@ using Disco.Models.Services.Jobs.JobQueues; using Disco.Models.UI.Config.JobQueue; using Disco.Services.Authorization; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Jobs.JobQueues; using Disco.Services.Plugins.Features.UIExtension; using Disco.Services.Web; @@ -28,7 +29,7 @@ namespace Disco.Web.Areas.Config.Controllers var token = JobQueueToken.FromJobQueue(jq); var subjects = token.SubjectIds == null ? new List() : - token.SubjectIds.Select(subjectId => Disco.BI.Interop.ActiveDirectory.ActiveDirectory.GetObject(subjectId)) + token.SubjectIds.Select(subjectId => ActiveDirectory.RetrieveObject(subjectId)) .Where(item => item != null) .Select(item => Models.JobQueue.ShowModel.SubjectDescriptor.FromActiveDirectoryObject(item)) .OrderBy(item => item.Name).ToList(); diff --git a/Disco.Web/Areas/Config/Controllers/SystemConfigController.cs b/Disco.Web/Areas/Config/Controllers/SystemConfigController.cs index d245fb63..809a7ea8 100644 --- a/Disco.Web/Areas/Config/Controllers/SystemConfigController.cs +++ b/Disco.Web/Areas/Config/Controllers/SystemConfigController.cs @@ -12,20 +12,5 @@ namespace Disco.Web.Areas.Config.Controllers var m = Models.SystemConfig.IndexModel.FromConfiguration(Database.DiscoConfiguration); return View(m); } - - [DiscoAuthorizeAll(Claims.Config.System.Show, Claims.Config.System.ConfigureProxy), HttpPost] - public virtual ActionResult Index(Models.SystemConfig.IndexModel config) - { - if (ModelState.IsValid) - { - config.ToConfiguration(Database); - return RedirectToAction(MVC.Config.Config.Index()); - } - else - { - return View(); - } - } - } } diff --git a/Disco.Web/Areas/Config/Models/AuthorizationRole/ShowModel.cs b/Disco.Web/Areas/Config/Models/AuthorizationRole/ShowModel.cs index b5d11873..a3da1092 100644 --- a/Disco.Web/Areas/Config/Models/AuthorizationRole/ShowModel.cs +++ b/Disco.Web/Areas/Config/Models/AuthorizationRole/ShowModel.cs @@ -40,7 +40,7 @@ namespace Disco.Web.Areas.Config.Models.AuthorizationRole { var item = new SubjectDescriptor() { - Id = ADObject.SamAccountName, + Id = ADObject.NetBiosId, Name = ADObject.Name }; diff --git a/Disco.Web/Areas/Config/Models/SystemConfig/IndexModel.cs b/Disco.Web/Areas/Config/Models/SystemConfig/IndexModel.cs index 7a522f0a..349467a8 100644 --- a/Disco.Web/Areas/Config/Models/SystemConfig/IndexModel.cs +++ b/Disco.Web/Areas/Config/Models/SystemConfig/IndexModel.cs @@ -8,6 +8,9 @@ using System.Data.SqlClient; using Disco.Data.Repository; using Disco.Models.BI.Interop.Community; using Disco.Services.Tasks; +using Disco.Models.Interop.ActiveDirectory; +using System.DirectoryServices.ActiveDirectory; +using Disco.Services.Interop.ActiveDirectory; namespace Disco.Web.Areas.Config.Models.SystemConfig { @@ -72,6 +75,20 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig } #endregion + #region Active Directory + + [Display(Name="Search Entire Forest")] + public bool ADSearchEntireForest { get; set; } + + public ActiveDirectoryDomain ADPrimaryDomain { get; set; } + public List ADAdditionalDomains { get; set; } + public ActiveDirectorySite ADSite { get; set; } + public List> ADSiteServers { get; set; } + public List> ADSearchContainers { get; set; } + public List ADForestServers { get; set; } + + #endregion + #region Proxy public string ProxyAddress { get; set; } public int ProxyPort { get; set; } @@ -87,7 +104,7 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig public static IndexModel FromConfiguration(SystemConfiguration config) { - return new IndexModel() + var m = new IndexModel() { DiscoVersion = typeof(DiscoApplication).Assembly.GetName().Version, DataStoreLocation = config.DataStoreLocation, @@ -100,27 +117,33 @@ namespace Disco.Web.Areas.Config.Models.SystemConfig UpdateNextScheduled = Disco.BI.Interop.Community.UpdateCheckTask.NextScheduled, UpdateBetaDeployment = config.UpdateBetaDeployment }; - } - public void ToConfiguration(DiscoDataContext Database) - { - SystemConfiguration config = Database.DiscoConfiguration; - //config.DataStoreLocation = DataStoreLocation; - config.ProxyAddress = ProxyAddress; - config.ProxyPort = ProxyPort; - config.ProxyUsername = ProxyUsername; - config.ProxyPassword = ProxyPassword; - DiscoApplication.SetGlobalProxy(ProxyAddress, ProxyPort, ProxyUsername, ProxyPassword); - - Database.SaveChanges(); - - // Try and check for updates if needed - After Proxy Changed - if (Database.DiscoConfiguration.UpdateLastCheck == null - || Database.DiscoConfiguration.UpdateLastCheck.ResponseTimestamp < DateTime.Now.AddDays(-1)) + // AD + m.ADPrimaryDomain = ActiveDirectory.PrimaryDomain; + m.ADAdditionalDomains = ActiveDirectory.Domains.Where(d => d != m.ADPrimaryDomain).ToList(); + m.ADSite = ActiveDirectory.Site; + m.ADSiteServers = m.ADSite.Servers.Cast().Select(s => Tuple.Create(s, s.Reachable())).ToList(); + var configSearchContainers = config.ActiveDirectory.SearchContainers; + m.ADSearchContainers = configSearchContainers == null ? null : configSearchContainers.Select(c => { - Disco.BI.Interop.Community.UpdateCheckTask.ScheduleNow(); - } - } + var d = ActiveDirectory.GetDomainByDistinguishedName(c); + return Tuple.Create(c, d, d.GetFriendlyOrganisationalUnitName(c)); + }).ToList(); + var loadForestServersTask = ActiveDirectory.LoadForestServersAsync(); + if (loadForestServersTask.Wait(TimeSpan.FromSeconds(3))) + { + m.ADForestServers = loadForestServersTask.Result; + var configValue = config.ActiveDirectory.SearchEntireForest ?? true; + m.ADSearchEntireForest = configValue && m.ADForestServers.Count <= ActiveDirectory.MaxForestServerSearch; + } + else + { + m.ADForestServers = null; + m.ADSearchEntireForest = config.ActiveDirectory.SearchEntireForest ?? true; + } + + return m; + } } } \ No newline at end of file diff --git a/Disco.Web/Areas/Config/Views/AuthorizationRole/Create.generated.cs b/Disco.Web/Areas/Config/Views/AuthorizationRole/Create.generated.cs index 5af4b2a3..402d35a4 100644 --- a/Disco.Web/Areas/Config/Views/AuthorizationRole/Create.generated.cs +++ b/Disco.Web/Areas/Config/Views/AuthorizationRole/Create.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/AuthorizationRole/Index.generated.cs b/Disco.Web/Areas/Config/Views/AuthorizationRole/Index.generated.cs index 4bdcac11..010e3849 100644 --- a/Disco.Web/Areas/Config/Views/AuthorizationRole/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/AuthorizationRole/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/AuthorizationRole/Show.generated.cs b/Disco.Web/Areas/Config/Views/AuthorizationRole/Show.generated.cs index 5a6c36f3..22c80abc 100644 --- a/Disco.Web/Areas/Config/Views/AuthorizationRole/Show.generated.cs +++ b/Disco.Web/Areas/Config/Views/AuthorizationRole/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -35,6 +35,7 @@ namespace Disco.Web.Areas.Config.Views.AuthorizationRole #line default #line hidden + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Config/Index.generated.cs b/Disco.Web/Areas/Config/Views/Config/Index.generated.cs index 2073ee4f..60d3f737 100644 --- a/Disco.Web/Areas/Config/Views/Config/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/Config/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Config using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceBatch/Create.generated.cs b/Disco.Web/Areas/Config/Views/DeviceBatch/Create.generated.cs index 1dbbf6b4..0e0bbf2a 100644 --- a/Disco.Web/Areas/Config/Views/DeviceBatch/Create.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceBatch/Create.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceBatch/Index.generated.cs b/Disco.Web/Areas/Config/Views/DeviceBatch/Index.generated.cs index 8086cdc0..7b92db4b 100644 --- a/Disco.Web/Areas/Config/Views/DeviceBatch/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceBatch/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceBatch/Show.generated.cs b/Disco.Web/Areas/Config/Views/DeviceBatch/Show.generated.cs index d957684d..fecaf2cb 100644 --- a/Disco.Web/Areas/Config/Views/DeviceBatch/Show.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceBatch/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceBatch/Timeline.generated.cs b/Disco.Web/Areas/Config/Views/DeviceBatch/Timeline.generated.cs index 14749c66..76483b3c 100644 --- a/Disco.Web/Areas/Config/Views/DeviceBatch/Timeline.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceBatch/Timeline.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceBatch using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceModel/GenericComponents.generated.cs b/Disco.Web/Areas/Config/Views/DeviceModel/GenericComponents.generated.cs index 2eb1fb98..2e5db0bd 100644 --- a/Disco.Web/Areas/Config/Views/DeviceModel/GenericComponents.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceModel/GenericComponents.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceModel/Index.generated.cs b/Disco.Web/Areas/Config/Views/DeviceModel/Index.generated.cs index 6aa63c7c..ab8064b0 100644 --- a/Disco.Web/Areas/Config/Views/DeviceModel/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceModel/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceModel/Show.generated.cs b/Disco.Web/Areas/Config/Views/DeviceModel/Show.generated.cs index fd9f036a..47e2d296 100644 --- a/Disco.Web/Areas/Config/Views/DeviceModel/Show.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceModel/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceModel/_DeviceComponentsTable.generated.cs b/Disco.Web/Areas/Config/Views/DeviceModel/_DeviceComponentsTable.generated.cs index d322a95c..d3d00c82 100644 --- a/Disco.Web/Areas/Config/Views/DeviceModel/_DeviceComponentsTable.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceModel/_DeviceComponentsTable.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceModel using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Create.cshtml b/Disco.Web/Areas/Config/Views/DeviceProfile/Create.cshtml index a49250ac..62f55fbb 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Create.cshtml +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Create.cshtml @@ -35,6 +35,7 @@ @Html.HiddenFor(model => model.DeviceProfile.ComputerNameTemplate) @Html.HiddenFor(model => model.DeviceProfile.ProvisionADAccount) @Html.HiddenFor(model => model.DeviceProfile.DistributionType) + @Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit)

diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Create.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/Create.generated.cs index c922771e..120e2435 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Create.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Create.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -174,6 +175,17 @@ WriteLiteral(" "); Write(Html.HiddenFor(model => model.DeviceProfile.DistributionType)); + #line default + #line hidden +WriteLiteral("\r\n"); + +WriteLiteral(" "); + + + #line 38 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml" + Write(Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit)); + + #line default #line hidden WriteLiteral("\r\n \r\n $(function () {\r\n $(\'#Name\').focus().s "\r\n \r\n"); - #line 47 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml" + #line 48 "..\..\Areas\Config\Views\DeviceProfile\Create.cshtml" } diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Defaults.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/Defaults.generated.cs index 667467e3..7e29ffb5 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Defaults.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Defaults.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Index.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/Index.generated.cs index 641498f9..3cad92ea 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Show.cshtml b/Disco.Web/Areas/Config/Views/DeviceProfile/Show.cshtml index e4479470..4396b767 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Show.cshtml +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Show.cshtml @@ -10,8 +10,8 @@ if (canConfig) { - Html.BundleDeferred("~/Style/jQueryUI/dynatree"); - Html.BundleDeferred("~/ClientScripts/Modules/jQueryUI-DynaTree"); + Html.BundleDeferred("~/Style/Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Fancytree"); } }
@@ -322,7 +322,8 @@ - Computer Name
Template Expression: + Computer Name
+ Template Expression: @if (canConfig && canConfigExpression) { @@ -517,125 +518,135 @@ - Default Organisational Unit: + Organisational Unit: @if (canConfig) { - @Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit) -
+
+ @if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit)) + { + {Default Computers Container} + } + else + { + var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit); + + + @Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit) + + }
Change@AjaxHelpers.AjaxLoader() -
-
+
+
} @@ -648,8 +659,10 @@ } else { + var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit); + - @string.Join(" > ", Model.DeviceProfile.OrganisationalUnit.Split(',').Select(s => s.Substring(3)).Reverse()) + @Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit) }
diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/Show.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/Show.generated.cs index a072b91a..e1110a5e 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/Show.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -56,8 +57,8 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile if (canConfig) { - Html.BundleDeferred("~/Style/jQueryUI/dynatree"); - Html.BundleDeferred("~/ClientScripts/Modules/jQueryUI-DynaTree"); + Html.BundleDeferred("~/Style/Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Fancytree"); } @@ -897,10 +898,10 @@ WriteLiteral("><None Allocated>\r\n"); #line default #line hidden WriteLiteral(" \r\n \r\n \r\n Computer Name
Template Expression:\r\n \r\n "); +"/>\r\n Template Expression:\r\n \r\n "); - #line 327 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 328 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig && canConfigExpression) { @@ -908,42 +909,42 @@ WriteLiteral(" \r\n \r\n \r\n #line default #line hidden - #line 329 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 330 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Html.TextBoxFor(model => model.DeviceProfile.ComputerNameTemplate)); #line default #line hidden - #line 329 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 330 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 330 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 331 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxSave()); #line default #line hidden - #line 330 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 331 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 331 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 332 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); #line default #line hidden - #line 331 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 332 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" @@ -953,14 +954,14 @@ WriteLiteral(" (Url.Action(MVC.Config.DocumentTemplate.ExpressionBrowser()) + #line 333 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" +, Tuple.Create(Tuple.Create("", 16277), Tuple.Create(Url.Action(MVC.Config.DocumentTemplate.ExpressionBrowser()) #line default #line hidden -, 16268), false) +, 16277), false) ); WriteLiteral("> \r\n"); @@ -991,7 +992,7 @@ WriteLiteral(@"> url: '"); - #line 352 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 353 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateComputerNameTemplate(Model.DeviceProfile.Id))); @@ -1019,7 +1020,7 @@ WriteLiteral(@"', "); - #line 371 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 372 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1036,13 +1037,13 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">\r\n"); - #line 375 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 376 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 375 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 376 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (string.IsNullOrWhiteSpace(Model.DeviceProfile.ComputerNameTemplate)) { @@ -1056,7 +1057,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral("><None Specified>\r\n"); - #line 378 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 379 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1065,14 +1066,14 @@ WriteLiteral("><None Specified>\r\n"); #line default #line hidden - #line 381 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 382 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.ComputerNameTemplate); #line default #line hidden - #line 381 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 382 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1082,7 +1083,7 @@ WriteLiteral("><None Specified>\r\n"); WriteLiteral("
\r\n"); - #line 384 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 385 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1095,13 +1096,13 @@ WriteLiteral(" style=\"margin-top: 8px;\""); WriteLiteral(">\r\n"); - #line 386 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 387 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 386 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 387 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { @@ -1117,7 +1118,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 388 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 389 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.EnforceComputerNameConvention ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1138,7 +1139,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 395 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 396 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateEnforceComputerNameConvention(Model.DeviceProfile.Id))); @@ -1158,7 +1159,7 @@ WriteLiteral(@"', data, function (response, result) { "); - #line 406 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 407 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1175,7 +1176,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 409 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 410 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.EnforceComputerNameConvention ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1184,7 +1185,7 @@ WriteLiteral(" "); WriteLiteral(" disabled=\"disabled\" />\r\n"); - #line 410 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 411 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1200,7 +1201,7 @@ WriteLiteral(">\r\n Enforce Naming Convention\r\n WriteLiteral(" "); - #line 414 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 415 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); @@ -1218,13 +1219,13 @@ WriteLiteral(">\r\n Note: Computer names are only changed whe "
\r\n"); - #line 425 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 426 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 425 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 426 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { @@ -1240,7 +1241,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 427 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 428 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.ProvisionADAccount ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1261,7 +1262,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 434 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 435 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateProvisionADAccount(Model.DeviceProfile.Id))); @@ -1281,7 +1282,7 @@ WriteLiteral(@"', data, function (response, result) { "); - #line 445 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 446 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1298,7 +1299,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 448 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 449 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.ProvisionADAccount ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1307,7 +1308,7 @@ WriteLiteral(" "); WriteLiteral(" disabled=\"disabled\" />\r\n"); - #line 449 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 450 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1323,7 +1324,7 @@ WriteLiteral(">\r\n Provision Active Directory Account\r\ WriteLiteral(" "); - #line 453 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 454 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); @@ -1336,13 +1337,13 @@ WriteLiteral(" style=\"margin-top: 8px;\""); WriteLiteral(">\r\n"); - #line 456 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 457 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 456 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 457 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { @@ -1358,7 +1359,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 458 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 459 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.AssignedUserLocalAdmin ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1379,7 +1380,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 465 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 466 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateAssignedUserLocalAdmin(Model.DeviceProfile.Id))); @@ -1399,7 +1400,7 @@ WriteLiteral(@"', data, function (response, result) { "); - #line 476 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 477 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1416,7 +1417,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 479 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 480 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.AssignedUserLocalAdmin ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1425,7 +1426,7 @@ WriteLiteral(" "); WriteLiteral(" disabled=\"disabled\" />\r\n"); - #line 480 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 481 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1441,7 +1442,7 @@ WriteLiteral(">\r\n Assigned User is Local Administrator\ WriteLiteral(" "); - #line 484 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 485 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); @@ -1454,13 +1455,13 @@ WriteLiteral(" style=\"margin-top: 8px;\""); WriteLiteral(">\r\n"); - #line 487 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 488 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 487 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 488 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { @@ -1476,7 +1477,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 489 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 490 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.AllowUntrustedReimageJobEnrolment ? new MvcHtmlString("checked=\"checked\" ") : null); @@ -1497,7 +1498,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 496 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 497 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateAllowUntrustedReimageJobEnrolment(Model.DeviceProfile.Id))); @@ -1517,7 +1518,7 @@ WriteLiteral(@"', data, function (response, result) { "); - #line 507 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 508 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1534,7 +1535,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 510 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 511 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.AllowUntrustedReimageJobEnrolment ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1543,7 +1544,7 @@ WriteLiteral(" "); WriteLiteral(" disabled=\"disabled\" />\r\n"); - #line 511 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 512 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1562,44 +1563,90 @@ WriteLiteral(">\'Software - Reimage\' Job is Open\r\n WriteLiteral(" "); - #line 515 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 516 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); #line default #line hidden WriteLiteral("\r\n
\r\n \r\n \r\n \r\n " + -" Default Organisational Unit:\r\n \r\n "); +" Organisational Unit:\r\n \r\n "); - #line 522 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 523 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { - - - #line default - #line hidden - - #line 524 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" - Write(Html.HiddenFor(model => model.DeviceProfile.OrganisationalUnit)); - - - #line default - #line hidden - - #line 524 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" - #line default #line hidden WriteLiteral(" \r\n
\r\n"); +WriteLiteral(" data-value=\""); + + + #line 525 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + Write(Model.DeviceProfile.OrganisationalUnit); + + + #line default + #line hidden +WriteLiteral("\""); + +WriteLiteral(">\r\n"); + + + #line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + + + #line default + #line hidden + + #line 526 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit)) + { + + + #line default + #line hidden +WriteLiteral(" {Default Computers Container}\r\n"); + + + #line 529 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + } + else + { + var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit); + + + + #line default + #line hidden +WriteLiteral(" \r\n"); + +WriteLiteral(" "); + + + #line 535 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)); + + + #line default + #line hidden +WriteLiteral("\r\n \r\n"); + + + #line 537 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + } + + + #line default + #line hidden +WriteLiteral("
\r\n"); WriteLiteral(" Change"); - #line 527 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 527 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); #line default #line hidden - #line 527 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 539 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" @@ -1635,117 +1682,113 @@ WriteLiteral(" \r\n \r\n \r\n \r\n"); WriteLiteral(" - $(function () { - var ouValue = $('#DeviceProfile_OrganisationalUnit'); - var ouDisplay = $('#displayOrganisationalUnit'); - var ouTree = $('#treeOrganisationalUnit'); - var ouChangeLink = $('#changeOrganisationalUnit'); - var ouTreeLoaded = false; - var ouFriendlyName = function (ou) { - return ou.replace(/ou=/gi, '').split(',').reverse().join(' > '); - }; - var updateDisplayOrganisationalUnit = function () { - var value = ouValue.val(); - if (value) { - ouDisplay.text(ouFriendlyName(value)); - } else { - ouDisplay.text('{Default Computers Container}'); - } - }; - var ouSet = function (ou) { - $ajaxLoading = ouChangeLink.next('.ajaxLoading').show(); - var data = { OrganisationalUnit: ou }; - $.getJSON('"); +WriteLiteral(">\r\n $(function () {\r\n var ouSetUrl = \'"); - #line 553 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" - Write(Url.Action(MVC.API.DeviceProfile.UpdateOrganisationalUnit(Model.DeviceProfile.Id, null))); + #line 546 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + Write(Url.Action(MVC.API.DeviceProfile.UpdateOrganisationalUnit(Model.DeviceProfile.Id, null, true))); #line default #line hidden -WriteLiteral("\', data, function (response, result) {\r\n if (resul" + -"t != \'success\' || response != \'OK\') {\r\n alert" + -"(\'Unable to change Organisational Unit:\\n\' + response);\r\n " + -" $ajaxLoading.hide();\r\n } else {\r\n " + -" ouValue.val(ou);\r\n " + -" updateDisplayOrganisationalUnit();\r\n $" + -"ajaxLoading.hide().next(\'.ajaxOk\').show().delay(\'fast\').fadeOut(\'slow\');\r\n " + -" }\r\n });\r\n " + -" }\r\n var ouUpdateTree = function () {\r\n " + -" var dynaTree = ouTree.dynatree(\"getTree\");\r\n " + -" var value = ouValue.val();\r\n if (value) {\r\n " + -" dynaTree.activateKey(value);\r\n " + -" } else {\r\n var activeNode = dynaTree.getAc" + -"tiveNode();\r\n if (activeNode)\r\n " + -" activeNode.deactivate();\r\n }\r\n " + -" }\r\n\r\n var ouDialog = $(\'#dialogOrganis" + -"ationalUnit\').dialog({\r\n autoOpen: false,\r\n " + -" buttons: {\r\n \'Use Default Conta" + -"iner\': function () {\r\n ouSet(\'\');\r\n " + -" $(this).dialog(\"close\");\r\n " + -" },\r\n \'Save\': function () {\r\n " + -" var node = ouTree.dynatree(\"getTree\").getActiveNode();\r\n " + -" if (node) {\r\n " + -" ouSet(node.data.key);\r\n $(this).dialo" + -"g(\"close\");\r\n } else {\r\n " + -" alert(\'Select an Organisational Unit to Save\')\r\n " + -" }\r\n }\r\n " + -" },\r\n draggable: false,\r\n " + -" modal: true,\r\n resizable: false,\r\n " + -" width: 400,\r\n height: 400\r\n " + -" });\r\n\r\n var ouChange = function () {\r\n " + -" if (!ouTreeLoaded) {\r\n $." + -"getJSON(\'"); +WriteLiteral("\';\r\n var ouValue = $(\'#DeviceProfile_OrganisationalUnit\')." + +"attr(\'data-value\');\r\n var $ouTree = null;\r\n " + +" var ouTree = null;\r\n var $dialog = null;\r\n " + +" var ouSet = function (ou) {\r\n var " + +"url = ouSetUrl + \'&\' + $.param({ OrganisationalUnit: ou })\r\n " + +" window.location.href = url;\r\n }\r\n " + +" var expandNodeTree = function (node) {\r\n var " + +"parent = node.parent;\r\n if (parent) {\r\n " + +" expandNodeTree(parent);\r\n paren" + +"t.setExpanded(true, { noAnimation: true, noEvents: false });\r\n " + +" }\r\n }\r\n var expandAndFoc" + +"usNode = function (nodeKey) {\r\n if (ouTree) {\r\n " + +" var ouNode = ouTree.getNodeByKey(ouValue);\r\n " + +" if (ouNode) {\r\n expandN" + +"odeTree(ouNode);\r\n ouNode.setFocus(true);\r\n " + +" ouNode.setActive(true);\r\n\r\n " + +" var li = ouNode.li;\r\n var li" + +"Offset = li.offsetParent;\r\n if (li.offsetTop " + +"+ li.offsetHeight > liOffset.offsetHeight)\r\n " + +" $(liOffset).animate({ \'scrollTop\': li.offsetTop - liOffset.offsetHeight + li" + +".offsetHeight + 4 }, \'fast\');\r\n }\r\n " + +" }\r\n }\r\n var ouChange" + +" = function () {\r\n if (!$dialog) {\r\n\r\n " + +" $dialog = $(\'#dialogOrganisationalUnit\').dialog({\r\n " + +" autoOpen: false,\r\n bu" + +"ttons: null,\r\n draggable: false,\r\n " + +" modal: true,\r\n resiz" + +"able: false,\r\n width: 500,\r\n " + +" height: 500\r\n });\r\n " + +" $ouTree = $(\'#treeOrganisationalUnit\');\r\n " + +" $dialog.css(\'overflow\', \'visible\');\r\n " + +" $ouTree.css(\'height\', \'100%\');\r\n\r\n $.getJSON(\'" + +""); - #line 602 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" - Write(Url.Action(MVC.API.DeviceProfile.OrganisationalUnits())); + #line 593 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + Write(Url.Action(MVC.API.System.DomainOrganisationalUnits())); #line default #line hidden -WriteLiteral("\', null, function (data) {\r\n var dynatreeDataTrans" + -"former = function (element) {\r\n var child = {" + -"\r\n title: element.Name,\r\n " + -" key: element.Path,\r\n " + -" isFolder: true\r\n }\r\n " + -" if (element.Children) {\r\n " + -"child.children = [];\r\n for (var i = 0; i " + -"< element.Children.length; i++) {\r\n c" + -"hild.children.push(dynatreeDataTransformer(element.Children[i]));\r\n " + -" }\r\n }\r\n " + -" return child;\r\n };\r\n " + -" var dynatreeData = [];\r\n " + -" for (var i = 0; i < data.length; i++) {\r\n " + -" dynatreeData.push(dynatreeDataTransformer(data[i]));\r\n " + -" }\r\n\r\n ouTree.dynatree({\r\n " + -" children: dynatreeData,\r\n " + -"onActivate: function (node) {\r\n //alert(\'" + -"node selected: \' + node.data.key);\r\n }\r\n " + -" });\r\n ouTreeLoaded = t" + -"rue;\r\n ouUpdateTree();\r\n " + -" });\r\n } else {\r\n ouUpdateTr" + -"ee();\r\n }\r\n ouDialog.dialog(\'o" + -"pen\');\r\n };\r\n\r\n ouChangeLink.click" + -"(ouChange);\r\n updateDisplayOrganisationalUnit();\r\n " + -" });\r\n \r\n"); +WriteLiteral("\', null, function (data) {\r\n\r\n // Make \'Domain" + +"s\' unselectable\r\n $.each(data, function (i, n" + +"ode) {\r\n node.unselectable = true;\r\n " + +" });\r\n\r\n ouTree" + +" = $ouTree.fancytree({\r\n source: data,\r\n " + +" checkbox: false,\r\n " + +" selectMode: 1,\r\n keyboar" + +"d: false,\r\n fx: null\r\n " + +" }).fancytree(\'getTree\');\r\n\r\n " + +" ouTree.$container.css(\'position\', \'relative\');\r\n\r\n " + +" // Set Buttons\r\n $dialog.dialog(\'optio" + +"n\', \'buttons\', {\r\n \'Use Default Container" + +"\': function () {\r\n var $this = $(this" + +");\r\n $this.css(\'overflow\', \'hidden\');" + +"\r\n $this.dialog(\"disable\");\r\n " + +" $this.dialog(\"option\", \"buttons\", null);\r\n " + +" ouSet(\'\');\r\n " + +" },\r\n \'Save\': function () {\r" + +"\n var node = ouTree.getActiveNode();\r" + +"\n if (node && node.key.substr(0, 3).t" + +"oLowerCase() == \'ou=\') {\r\n var $t" + +"his = $(this);\r\n $this.css(\'overf" + +"low\', \'hidden\');\r\n $this.dialog(\"" + +"disable\");\r\n $this.dialog(\"option" + +"\", \"buttons\", null);\r\n ouSet(node" + +".key);\r\n } else {\r\n " + +" alert(\'Select an Organisational Unit to Save\')\r\n " + +" }\r\n " + +" }\r\n });\r\n\r\n " + +" // Expand\r\n expandAndFocusNode(ouValue" + +");\r\n\r\n ouTree.options.fx = { height: \"toggle\"" + +", duration: 200 };\r\n });\r\n " + +" }\r\n $dialog.dialog(\'open\');\r\n\r\n " + +" if (ouTree) {\r\n // Expand\r\n " + +" expandAndFocusNode(ouValue);\r\n }" + +"\r\n\r\n return false;\r\n };\r\n\r\n " + +" $(\'#changeOrganisationalUnit\').click(ouChange);\r\n " + +" });\r\n \r\n"); - #line 641 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 652 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1762,13 +1805,13 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">\r\n"); - #line 645 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 656 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 645 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 656 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (string.IsNullOrEmpty(Model.DeviceProfile.OrganisationalUnit)) { @@ -1778,10 +1821,12 @@ WriteLiteral(">\r\n"); WriteLiteral(" {Default Computers Container}\r\n"); - #line 648 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 659 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { + var domain = Disco.Services.Interop.ActiveDirectory.ActiveDirectory.GetDomainByDistinguishedName(Model.DeviceProfile.OrganisationalUnit); + #line default @@ -1791,8 +1836,8 @@ WriteLiteral(" \r\n"); WriteLiteral(" "); - #line 652 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" - Write(string.Join(" > ", Model.DeviceProfile.OrganisationalUnit.Split(',').Select(s => s.Substring(3)).Reverse())); + #line 665 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectoryExtensions.GetFriendlyOrganisationalUnitName(domain, Model.DeviceProfile.OrganisationalUnit)); #line default @@ -1800,7 +1845,7 @@ WriteLiteral(" "); WriteLiteral("\r\n \r\n"); - #line 654 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 667 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1809,7 +1854,7 @@ WriteLiteral("\r\n \r\n"); WriteLiteral(" \r\n"); - #line 656 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 669 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1822,13 +1867,13 @@ WriteLiteral(" style=\"margin-top: 8px;\""); WriteLiteral(">\r\n"); - #line 658 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 671 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 658 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 671 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canConfig) { @@ -1844,7 +1889,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 660 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 673 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1865,7 +1910,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 667 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 680 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Url.Action(MVC.API.DeviceProfile.UpdateEnforceOrganisationalUnit(Model.DeviceProfile.Id))); @@ -1885,7 +1930,7 @@ WriteLiteral(@"', data, function (response, result) { "); - #line 678 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 691 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } else { @@ -1902,7 +1947,7 @@ WriteLiteral(" type=\"checkbox\""); WriteLiteral(" "); - #line 681 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 694 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Model.DeviceProfile.EnforceOrganisationalUnit ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)); @@ -1911,7 +1956,7 @@ WriteLiteral(" "); WriteLiteral(" disabled=\"disabled\" />\r\n"); - #line 682 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 695 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -1927,7 +1972,7 @@ WriteLiteral(">\r\n Enforce Organisational Unit\r\n WriteLiteral(" "); - #line 686 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 699 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(AjaxHelpers.AjaxLoader()); @@ -1937,7 +1982,7 @@ WriteLiteral("\r\n \r\n \r\n \r "\n"); - #line 692 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 705 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canDelete) { @@ -1992,7 +2037,7 @@ WriteLiteral(@"> "); - #line 728 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 741 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -2005,13 +2050,13 @@ WriteLiteral(" class=\"actionBar\""); WriteLiteral(">\r\n"); - #line 730 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 743 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" #line default #line hidden - #line 730 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 743 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (canDelete) { @@ -2019,14 +2064,14 @@ WriteLiteral(">\r\n"); #line default #line hidden - #line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 745 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Html.ActionLinkButton("Delete", MVC.API.DeviceProfile.Delete(Model.DeviceProfile.Id, true), "buttonDelete")); #line default #line hidden - #line 732 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 745 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -2036,7 +2081,7 @@ WriteLiteral(">\r\n"); WriteLiteral(" "); - #line 734 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 747 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (Authorization.Has(Claims.Device.Actions.Export)) { @@ -2044,14 +2089,14 @@ WriteLiteral(" "); #line default #line hidden - #line 736 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 749 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Html.ActionLinkButton("Export Devices", MVC.API.DeviceProfile.ExportDevices(Model.DeviceProfile.Id))); #line default #line hidden - #line 736 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 749 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } @@ -2061,7 +2106,7 @@ WriteLiteral(" "); WriteLiteral(" "); - #line 738 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 751 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" if (Authorization.Has(Claims.Device.Search)) { @@ -2069,14 +2114,14 @@ WriteLiteral(" "); #line default #line hidden - #line 740 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 753 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" Write(Html.ActionLinkButton("View Devices", MVC.Search.Query(Model.DeviceProfile.Id.ToString(), "DeviceProfile"))); #line default #line hidden - #line 740 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" + #line 753 "..\..\Areas\Config\Views\DeviceProfile\Show.cshtml" } diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/_Table.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/_Table.generated.cs index 22d45fbe..68b5172e 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/_Table.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/_Table.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DeviceProfile/_TableRender.generated.cs b/Disco.Web/Areas/Config/Views/DeviceProfile/_TableRender.generated.cs index 479c858f..c1eb28fc 100644 --- a/Disco.Web/Areas/Config/Views/DeviceProfile/_TableRender.generated.cs +++ b/Disco.Web/Areas/Config/Views/DeviceProfile/_TableRender.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DeviceProfile using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/Create.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/Create.generated.cs index 7ce920b0..d473e5d1 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/Create.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/Create.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/ExpressionBrowser2.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/ExpressionBrowser2.generated.cs index aaf32163..8c348d79 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/ExpressionBrowser2.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/ExpressionBrowser2.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/ImportStatus.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/ImportStatus.generated.cs index 0da62411..5031ed0c 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/ImportStatus.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/ImportStatus.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/Index.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/Index.generated.cs index 234e920a..f28b875c 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/Show.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/Show.generated.cs index 0342619c..2af3f063 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/Show.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/UndetectedPages.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/UndetectedPages.generated.cs index 71a8dcae..e7f4c277 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/UndetectedPages.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/UndetectedPages.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.generated.cs b/Disco.Web/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.generated.cs index a34dddb1..c4195b98 100644 --- a/Disco.Web/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.generated.cs +++ b/Disco.Web/Areas/Config/Views/DocumentTemplate/_ExpressionsTable.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.DocumentTemplate using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Enrolment/Index.generated.cs b/Disco.Web/Areas/Config/Views/Enrolment/Index.generated.cs index 7d2ceba7..11e00994 100644 --- a/Disco.Web/Areas/Config/Views/Enrolment/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/Enrolment/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Enrolment using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Enrolment/Status.generated.cs b/Disco.Web/Areas/Config/Views/Enrolment/Status.generated.cs index 1c7c4794..165c2cfb 100644 --- a/Disco.Web/Areas/Config/Views/Enrolment/Status.generated.cs +++ b/Disco.Web/Areas/Config/Views/Enrolment/Status.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Enrolment using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs b/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs index cfddd182..d8f3b6e8 100644 --- a/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs +++ b/Disco.Web/Areas/Config/Views/Expressions/Editor.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Expressions using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/JobQueue/Create.generated.cs b/Disco.Web/Areas/Config/Views/JobQueue/Create.generated.cs index 75fad008..fe4998b0 100644 --- a/Disco.Web/Areas/Config/Views/JobQueue/Create.generated.cs +++ b/Disco.Web/Areas/Config/Views/JobQueue/Create.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.JobQueue using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/JobQueue/Index.generated.cs b/Disco.Web/Areas/Config/Views/JobQueue/Index.generated.cs index 7ed833bd..15d13f25 100644 --- a/Disco.Web/Areas/Config/Views/JobQueue/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/JobQueue/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.JobQueue using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Logging/Index.generated.cs b/Disco.Web/Areas/Config/Views/Logging/Index.generated.cs index af849e0c..28610888 100644 --- a/Disco.Web/Areas/Config/Views/Logging/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/Logging/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Logging using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; #line 2 "..\..\Areas\Config\Views\Logging\Index.cshtml" diff --git a/Disco.Web/Areas/Config/Views/Logging/TaskStatus.generated.cs b/Disco.Web/Areas/Config/Views/Logging/TaskStatus.generated.cs index 2c989a46..6a452c2f 100644 --- a/Disco.Web/Areas/Config/Views/Logging/TaskStatus.generated.cs +++ b/Disco.Web/Areas/Config/Views/Logging/TaskStatus.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Logging using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Organisation/Index.generated.cs b/Disco.Web/Areas/Config/Views/Organisation/Index.generated.cs index 733a74fd..3bfbf202 100644 --- a/Disco.Web/Areas/Config/Views/Organisation/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/Organisation/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Organisation using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Plugins/Index.generated.cs b/Disco.Web/Areas/Config/Views/Plugins/Index.generated.cs index 553077e5..17298861 100644 --- a/Disco.Web/Areas/Config/Views/Plugins/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/Plugins/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Plugins using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; #line 2 "..\..\Areas\Config\Views\Plugins\Index.cshtml" diff --git a/Disco.Web/Areas/Config/Views/Plugins/Install.generated.cs b/Disco.Web/Areas/Config/Views/Plugins/Install.generated.cs index a5e67cb4..e9638484 100644 --- a/Disco.Web/Areas/Config/Views/Plugins/Install.generated.cs +++ b/Disco.Web/Areas/Config/Views/Plugins/Install.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Plugins using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; #line 2 "..\..\Areas\Config\Views\Plugins\Install.cshtml" diff --git a/Disco.Web/Areas/Config/Views/Plugins/ProviderConfiguration.generated.cs b/Disco.Web/Areas/Config/Views/Plugins/ProviderConfiguration.generated.cs index 4056e237..b48ecc02 100644 --- a/Disco.Web/Areas/Config/Views/Plugins/ProviderConfiguration.generated.cs +++ b/Disco.Web/Areas/Config/Views/Plugins/ProviderConfiguration.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Plugins using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/Shared/LogEvents.generated.cs b/Disco.Web/Areas/Config/Views/Shared/LogEvents.generated.cs index 8539eff1..64c01810 100644 --- a/Disco.Web/Areas/Config/Views/Shared/LogEvents.generated.cs +++ b/Disco.Web/Areas/Config/Views/Shared/LogEvents.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.Shared using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Config/Views/SystemConfig/Index.cshtml b/Disco.Web/Areas/Config/Views/SystemConfig/Index.cshtml index 27c1bb1f..4911567a 100644 --- a/Disco.Web/Areas/Config/Views/SystemConfig/Index.cshtml +++ b/Disco.Web/Areas/Config/Views/SystemConfig/Index.cshtml @@ -3,8 +3,16 @@ Authorization.Require(Claims.Config.System.Show); var canConfigProxy = Authorization.Has(Claims.Config.System.ConfigureProxy); + var canConfigAD = Authorization.Has(Claims.Config.System.ConfigureActiveDirectory); ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "System"); + + if (canConfigAD) + { + Html.BundleDeferred("~/Style/Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers"); + } }
@@ -133,9 +141,296 @@
+
+

Active Directory

+ + + + + + + + + + + + + + + + + + + + + +
Primary Domain: + + @Model.ADPrimaryDomain.DnsName [@Model.ADPrimaryDomain.NetBiosName] +
Additional Domains: + + @if (Model.ADAdditionalDomains.Count > 0) + { + var adDomainFirst = Model.ADAdditionalDomains.First(); + @adDomainFirst.DnsName [@adDomainFirst.NetBiosName] + foreach (var adDomain in Model.ADAdditionalDomains.Skip(1)) + { +
+
+ @adDomain.DnsName [@adDomain.NetBiosName] +
+ } + } + else + { + <None> + } +
Site: + + @Model.ADSite.Name +
+
+ @if (Model.ADSiteServers.Count > 0) + { + Servers: +
    + @foreach (var siteServer in Model.ADSiteServers) + { + var server = siteServer.Item1; + var reachable = siteServer.Item2; +
  • +  @(server.Name) +
  • + } +
+ } + else + { +
+  None Found +
+ } +
+
Forest: + + @if (Model.ADForestServers == null) + { +
+ @Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest) +
+
+  Forest servers are being retrieved, try refreshing this page in a moment. +
+ } + else + { + if (canConfigAD) + { + var canSearchEntireForest = (Model.ADForestServers.Count <= Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch); +
+ @if (!canSearchEntireForest) + { + @Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest) +
+  Disco will not search entire forests which consist of more than @(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch) servers. Only servers within this site will be searched. +
+ } + else + { + @Html.CheckBoxFor(m => m.ADSearchEntireForest) @Html.LabelFor(m => m.ADSearchEntireForest) @AjaxHelpers.AjaxLoader() +
+ If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site. +
+ + } +
+ } + else + { +
+ @Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" }) @Html.LabelFor(m => m.ADSearchEntireForest) +
+ If this setting is enabled, Disco will search all servers within the forest rather than only servers within this site. +
+
+ } +
+
+ Servers: +
    + @foreach (var server in Model.ADForestServers.OrderBy(s => s)) + { +
  • @server @(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null)
  • + } +
+ +
+ } +
Search Scope: + + @if (Model.ADSearchContainers != null && Model.ADSearchContainers.Count > 0) + { +
Searching is restricted to the following Organisational Unit containers
+
    + @foreach (var adContainer in Model.ADSearchContainers) + { +
  • @adContainer.Item3
  • + } +
+ } + else + { +
No restrictions are in effect.
+
When searching, the entire domain will be queried. This is suitable for most single-domain deployments.
+ } + @if (canConfigAD) + { +
+
+ Update +
+
+
+
+ @using (Html.BeginForm(MVC.API.System.UpdateActiveDirectorySearchScope(null, redirect: true))) + { + } +
+ + } +
+
@if (canConfigProxy) { - using (Html.BeginForm()) + using (Html.BeginForm(MVC.API.System.UpdateProxySettings())) {

Proxy Settings

diff --git a/Disco.Web/Areas/Config/Views/SystemConfig/Index.generated.cs b/Disco.Web/Areas/Config/Views/SystemConfig/Index.generated.cs index 9b25efe1..1bdd3310 100644 --- a/Disco.Web/Areas/Config/Views/SystemConfig/Index.generated.cs +++ b/Disco.Web/Areas/Config/Views/SystemConfig/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34014 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views.SystemConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -49,9 +50,17 @@ namespace Disco.Web.Areas.Config.Views.SystemConfig Authorization.Require(Claims.Config.System.Show); var canConfigProxy = Authorization.Has(Claims.Config.System.ConfigureProxy); + var canConfigAD = Authorization.Has(Claims.Config.System.ConfigureActiveDirectory); ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "System"); + if (canConfigAD) + { + Html.BundleDeferred("~/Style/Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Fancytree"); + Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers"); + } + #line default #line hidden @@ -69,7 +78,7 @@ WriteLiteral(">Disco Version:\r\n \r\n \r\n " "); - #line 16 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 24 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DiscoVersion.ToString(4)); @@ -79,20 +88,20 @@ WriteLiteral("\r\n
\r\n (Model.DiscoVersionBuilt.ToFullDateTime() + #line 26 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" +, Tuple.Create(Tuple.Create("", 961), Tuple.Create(Model.DiscoVersionBuilt.ToFullDateTime() #line default #line hidden -, 624), false) +, 961), false) ); WriteLiteral(">\r\n Built "); - #line 19 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 27 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(CommonHelpers.FriendlyDate(Model.DiscoVersionBuilt, "Unknown")); @@ -116,7 +125,7 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">"); - #line 30 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 38 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DatabaseServer); @@ -130,7 +139,7 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">"); - #line 34 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 42 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DatabaseName); @@ -140,7 +149,7 @@ WriteLiteral("\r\n \r\n < " Authentication:\r\n "); - #line 38 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 46 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DatabaseAuthentication); @@ -149,13 +158,13 @@ WriteLiteral("\r\n \r\n < WriteLiteral("\r\n \r\n"); - #line 40 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 48 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" #line default #line hidden - #line 40 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 48 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (Model.DatabaseSqlAuthUsername != null) { @@ -170,7 +179,7 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">"); - #line 44 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 52 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DatabaseSqlAuthUsername); @@ -179,7 +188,7 @@ WriteLiteral(">"); WriteLiteral("\r\n \r\n"); - #line 46 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 54 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } @@ -198,7 +207,7 @@ WriteLiteral(" class=\"code\""); WriteLiteral(">"); - #line 55 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 63 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.DataStoreLocation); @@ -213,13 +222,13 @@ WriteLiteral(" style=\"width: 450px; margin-top: 15px;\""); WriteLiteral(">\r\n

Updates

\r\n \r\n"); - #line 63 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 71 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" #line default #line hidden - #line 63 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 71 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (Model.UpdateLatestResponse == null) { @@ -243,7 +252,7 @@ WriteLiteral(" class=\"fa fa-exclamation-circle fa-lg\""); WriteLiteral("> Never\r\n \r\n \r\n"); - #line 73 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 81 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } else { @@ -259,7 +268,7 @@ WriteLiteral(">Last Run:\r\n \r\n \r\n \r\n"); - #line 83 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 91 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (Model.UpdateLatestResponse.IsUpdatable(typeof(DiscoApplication).Assembly.GetName().Version)) { @@ -287,7 +296,7 @@ WriteLiteral(" class=\"fa fa-info-circle fa-lg information\""); WriteLiteral("> Version "); - #line 90 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 98 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Model.UpdateLatestResponse.Version); @@ -300,7 +309,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">\r\n [Released "); - #line 93 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 101 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(CommonHelpers.FriendlyDate(Model.UpdateLatestResponse.VersionReleasedTimestamp)); @@ -313,7 +322,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">"); - #line 95 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 103 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(new HtmlString(Model.UpdateLatestResponse.Blurb)); @@ -321,14 +330,14 @@ WriteLiteral(">"); #line hidden WriteLiteral("\r\n (Model.UpdateLatestResponse.UrlLink + #line 104 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" +, Tuple.Create(Tuple.Create("", 4003), Tuple.Create(Model.UpdateLatestResponse.UrlLink #line default #line hidden -, 3666), false) +, 4003), false) ); WriteLiteral(" target=\"_blank\""); @@ -336,7 +345,7 @@ WriteLiteral(" target=\"_blank\""); WriteLiteral(">Download Now\r\n \r\n \r\n"); - #line 99 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 107 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } else { @@ -356,7 +365,7 @@ WriteLiteral("> The latest version is installed\r\n " \r\n"); - #line 109 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 117 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } } @@ -370,13 +379,13 @@ WriteLiteral(" style=\"width: 135px\""); WriteLiteral(">Check for Update:\r\n \r\n \r\n
\r\n "n>"); - #line 80 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 88 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(CommonHelpers.FriendlyDate(Model.UpdateLatestResponse.ResponseTimestamp)); @@ -268,7 +277,7 @@ WriteLiteral(">Last Run:\r\n \r\n \r\n WriteLiteral("\r\n
\r\n"); - #line 115 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 123 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" #line default #line hidden - #line 115 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 123 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (Model.UpdateRunningStatus == null) { @@ -387,7 +396,7 @@ WriteLiteral(">Check for Update:\r\n \r\n"); WriteLiteral(" "); - #line 118 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 126 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ActionLinkSmallButton("Check Now", MVC.API.System.UpdateCheck())); @@ -402,7 +411,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">[Will run automatically "); - #line 119 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 127 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(CommonHelpers.FriendlyDate(Model.UpdateNextScheduled, "Unknown")); @@ -411,7 +420,7 @@ WriteLiteral(">[Will run automatically "); WriteLiteral("]\r\n"); - #line 120 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 128 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } else { @@ -422,7 +431,7 @@ WriteLiteral("]\r\n"); WriteLiteral(" "); - #line 123 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 131 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ActionLink("View Status", MVC.Config.Logging.TaskStatus(Model.UpdateRunningStatus.SessionId))); @@ -437,7 +446,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">[Running Now]\r\n"); - #line 125 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 133 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } @@ -446,13 +455,13 @@ WriteLiteral(">[Running Now]\r\n"); WriteLiteral("\r\n"); - #line 127 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 135 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" #line default #line hidden - #line 127 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 135 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (Model.UpdateBetaDeployment) { @@ -472,7 +481,833 @@ WriteLiteral(" class=\"fa fa-info-circle fa-lg\""); WriteLiteral("> Beta Deployment\r\n"); - #line 131 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 139 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral("
\r\n\r\n\r\n

Active Directory

\r\n \r\n \r\n Primary Domain:\r\n \r\n \r\n \r\n \r\n Additional Domains:\r\n \r\n \r\n \r\n \r\n Site:\r\n \r\n \r\n \r\n \r\n " + +" Forest:\r\n \r\n \r\n \r\n \r\n Search Scope:\r\n \r\n \r\n \r\n
\r\n "); + + + #line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Model.ADPrimaryDomain.DnsName); + + + #line default + #line hidden +WriteLiteral(" ["); + + + #line 151 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Model.ADPrimaryDomain.NetBiosName); + + + #line default + #line hidden +WriteLiteral("]\r\n
\r\n"); + + + #line 158 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 158 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + if (Model.ADAdditionalDomains.Count > 0) + { + var adDomainFirst = Model.ADAdditionalDomains.First(); + + + #line default + #line hidden +WriteLiteral(" "); + + + #line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(adDomainFirst.DnsName); + + + #line default + #line hidden +WriteLiteral(" ["); + + + #line 161 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(adDomainFirst.NetBiosName); + + + #line default + #line hidden +WriteLiteral("]\r\n"); + + + #line 162 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + foreach (var adDomain in Model.ADAdditionalDomains.Skip(1)) + { + + + #line default + #line hidden +WriteLiteral("
\r\n"); + +WriteLiteral("
\r\n "); + + + #line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(adDomain.DnsName); + + + #line default + #line hidden +WriteLiteral(" ["); + + + #line 166 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(adDomain.NetBiosName); + + + #line default + #line hidden +WriteLiteral("]\r\n
\r\n"); + + + #line 168 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + } + else + { + + + #line default + #line hidden +WriteLiteral(" <None>\r\n"); + + + #line 173 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral("
\r\n "); + + + #line 180 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Model.ADSite.Name); + + + #line default + #line hidden +WriteLiteral("\r\n
\r\n
\r\n"); + + + #line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 183 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + if (Model.ADSiteServers.Count > 0) + { + + + #line default + #line hidden +WriteLiteral(" Servers:\r\n"); + +WriteLiteral(" \r\n"); + + + #line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 187 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + foreach (var siteServer in Model.ADSiteServers) + { + var server = siteServer.Item1; + var reachable = siteServer.Item2; + + + #line default + #line hidden +WriteLiteral("
  • \r\n (reachable ? "fa-check success" : "fa-exclamation warning" + + #line default + #line hidden +, 7482), false) +, Tuple.Create(Tuple.Create(" ", 7542), Tuple.Create("fa-fw", 7543), true) +, Tuple.Create(Tuple.Create(" ", 7548), Tuple.Create("fa-lg", 7549), true) +); + +WriteAttribute("title", Tuple.Create(" title=\"", 7555), Tuple.Create("\"", 7605) + + #line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + , Tuple.Create(Tuple.Create("", 7563), Tuple.Create(reachable ? "Reachable" : "Unavailable" + + #line default + #line hidden +, 7563), false) +); + +WriteLiteral("> "); + + + #line 192 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(server.Name); + + + #line default + #line hidden +WriteLiteral("\r\n
  • \r\n"); + + + #line 194 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral(" \r\n"); + + + #line 196 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + else + { + + + #line default + #line hidden +WriteLiteral(" \r\n  None Found\r\n
    \r\n"); + + + #line 202 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral(" \r\n
    \r\n"); + + + #line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 210 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + if (Model.ADForestServers == null) + { + + + #line default + #line hidden +WriteLiteral("
    \r\n"); + +WriteLiteral(" "); + + + #line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" })); + + + #line default + #line hidden +WriteLiteral(" "); + + + #line 213 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.LabelFor(m => m.ADSearchEntireForest)); + + + #line default + #line hidden +WriteLiteral("\r\n
    \r\n"); + +WriteLiteral(" \r\n  Forest servers are being retrieved, try refreshing this page in a mome" + +"nt.\r\n \r\n"); + + + #line 218 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + else + { + if (canConfigAD) + { + var canSearchEntireForest = (Model.ADForestServers.Count <= Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch); + + + #line default + #line hidden +WriteLiteral("
    \r\n"); + + + #line 225 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 225 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + if (!canSearchEntireForest) + { + + + #line default + #line hidden + + #line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" })); + + + #line default + #line hidden + + #line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.LabelFor(m => m.ADSearchEntireForest)); + + + #line default + #line hidden + + #line 227 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + + #line default + #line hidden +WriteLiteral(" \r\n  Disco will not search entire forests which consist of more than "); + + + #line 229 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Disco.Services.Interop.ActiveDirectory.ActiveDirectory.MaxForestServerSearch); + + + #line default + #line hidden +WriteLiteral(" servers. Only servers within this site will be searched.\r\n " + +"
    \r\n"); + + + #line 231 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + else + { + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.CheckBoxFor(m => m.ADSearchEntireForest)); + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.LabelFor(m => m.ADSearchEntireForest)); + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(AjaxHelpers.AjaxLoader()); + + + #line default + #line hidden + + #line 234 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + + #line default + #line hidden +WriteLiteral(" \r\n If this setting is enabled, Disco will search " + +"all servers within the forest rather than only servers within this site.\r\n " + +" \r\n"); + +WriteLiteral(" \r\n"); + + + #line 243 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral(" \r\n"); + + + #line 245 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + else + { + + + #line default + #line hidden +WriteLiteral("
    \r\n"); + +WriteLiteral(" "); + + + #line 249 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.CheckBoxFor(m => m.ADSearchEntireForest, new { disabled = "disabled" })); + + + #line default + #line hidden +WriteLiteral(" "); + + + #line 249 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Html.LabelFor(m => m.ADSearchEntireForest)); + + + #line default + #line hidden +WriteLiteral("\r\n \r\n If this setting is enabled, Disco will search all " + +"servers within the forest rather than only servers within this site.\r\n " + +"
    \r\n \r\n"); + + + #line 254 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral("
    \r\n
    \r\n " + +" Servers:\r\n \r\n"); + + + #line 259 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 259 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + foreach (var server in Model.ADForestServers.OrderBy(s => s)) + { + + + #line default + #line hidden +WriteLiteral("
  • "); + + + #line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(server); + + + #line default + #line hidden +WriteLiteral(" "); + + + #line 261 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + Write(Model.ADSiteServers.Count(ss => ss.Item1.Name.Equals(server, StringComparison.InvariantCultureIgnoreCase)) > 0 ? "[Site Server]" : null); + + + #line default + #line hidden +WriteLiteral("
  • \r\n"); + + + #line 262 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral(@" + +
    +"); + + + #line 287 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + } + + + #line default + #line hidden +WriteLiteral("
    \r\n"); + + + #line 294 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 294 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + if (Model.ADSearchContainers != null && Model.ADSearchContainers.Count > 0) + { + + + #line default + #line hidden +WriteLiteral("
    Searching is restricted to the following Organisational&" + +"nbsp;Unit containers
    \r\n"); + +WriteLiteral(" \r\n"); + + + #line 298 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + + + #line default + #line hidden + + #line 298 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + foreach (var adContainer in Model.ADSearchContainers) + { + + + #line default + #line hidden +WriteLiteral("
    \r\n\r\n"); - #line 136 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 431 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" if (canConfigProxy) { - using (Html.BeginForm()) + using (Html.BeginForm(MVC.API.System.UpdateProxySettings())) { @@ -506,7 +1341,7 @@ WriteLiteral(">Address:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 147 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 442 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.EditorFor(m => m.ProxyAddress)); @@ -517,7 +1352,7 @@ WriteLiteral("
    \r\n"); WriteLiteral(" "); - #line 148 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 443 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ValidationMessageFor(m => m.ProxyAddress)); @@ -533,7 +1368,7 @@ WriteLiteral(">Port:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 155 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 450 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.EditorFor(m => m.ProxyPort)); @@ -544,7 +1379,7 @@ WriteLiteral("
    \r\n"); WriteLiteral(" "); - #line 156 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 451 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ValidationMessageFor(m => m.ProxyPort)); @@ -560,7 +1395,7 @@ WriteLiteral(">Username:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 163 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 458 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.EditorFor(m => m.ProxyUsername)); @@ -571,7 +1406,7 @@ WriteLiteral("
    \r\n"); WriteLiteral(" "); - #line 164 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 459 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ValidationMessageFor(m => m.ProxyUsername)); @@ -587,7 +1422,7 @@ WriteLiteral(">Password:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 171 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 466 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.EditorFor(m => m.ProxyPassword)); @@ -598,7 +1433,7 @@ WriteLiteral("
    \r\n"); WriteLiteral(" "); - #line 172 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 467 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ValidationMessageFor(m => m.ProxyPassword)); @@ -620,7 +1455,7 @@ WriteLiteral(" value=\"Save Proxy Settings\""); WriteLiteral(" />\r\n \r\n \r\n \r\n \r\n"); - #line 184 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 479 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } } else @@ -645,7 +1480,7 @@ WriteLiteral(">Address:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 195 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 490 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.DisplayFor(m => m.ProxyAddress)); @@ -661,7 +1496,7 @@ WriteLiteral(">Port:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 202 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 497 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.DisplayFor(m => m.ProxyPort)); @@ -677,7 +1512,7 @@ WriteLiteral(">Username:\r\n \r\n \r\n"); WriteLiteral(" "); - #line 209 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 504 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.DisplayFor(m => m.ProxyUsername)); @@ -692,7 +1527,7 @@ WriteLiteral(">Password:\r\n \r\n ******* "\r\n \r\n \r\n \r\n"); - #line 220 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 515 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" } @@ -707,7 +1542,7 @@ WriteLiteral(">\r\n"); WriteLiteral(" "); - #line 222 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" + #line 517 "..\..\Areas\Config\Views\SystemConfig\Index.cshtml" Write(Html.ActionLinkButton("Update Device Last Network Logons", MVC.API.System.UpdateLastNetworkLogonDates())); diff --git a/Disco.Web/Areas/Config/Views/Web.config b/Disco.Web/Areas/Config/Views/Web.config index ec1c9143..055e8782 100644 --- a/Disco.Web/Areas/Config/Views/Web.config +++ b/Disco.Web/Areas/Config/Views/Web.config @@ -33,6 +33,11 @@ + + + + + diff --git a/Disco.Web/Areas/Config/Views/_ViewStart.generated.cs b/Disco.Web/Areas/Config/Views/_ViewStart.generated.cs index 470afd22..684174aa 100644 --- a/Disco.Web/Areas/Config/Views/_ViewStart.generated.cs +++ b/Disco.Web/Areas/Config/Views/_ViewStart.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Areas.Config.Views using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Controllers/HeldDevicesController.cs b/Disco.Web/Areas/Public/Controllers/HeldDevicesController.cs index ce43e8ad..4a70bc30 100644 --- a/Disco.Web/Areas/Public/Controllers/HeldDevicesController.cs +++ b/Disco.Web/Areas/Public/Controllers/HeldDevicesController.cs @@ -20,7 +20,7 @@ namespace Disco.Web.Areas.Public.Controllers { JobId = j.Id, DeviceSerialNumber = j.DeviceSerialNumber, - DeviceComputerName = j.Device.ComputerName, + DeviceComputerName = j.Device.DeviceDomainId, DeviceLocation = j.Device.Location, DeviceProfileId = j.Device.DeviceProfileId, DeviceAddressId = j.Device.DeviceProfile.DefaultOrganisationAddress, diff --git a/Disco.Web/Areas/Public/Views/HeldDevices/Index.generated.cs b/Disco.Web/Areas/Public/Views/HeldDevices/Index.generated.cs index b26a4b59..61d7c324 100644 --- a/Disco.Web/Areas/Public/Views/HeldDevices/Index.generated.cs +++ b/Disco.Web/Areas/Public/Views/HeldDevices/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/HeldDevices/Noticeboard.generated.cs b/Disco.Web/Areas/Public/Views/HeldDevices/Noticeboard.generated.cs index 8a996a29..0bfb809a 100644 --- a/Disco.Web/Areas/Public/Views/HeldDevices/Noticeboard.generated.cs +++ b/Disco.Web/Areas/Public/Views/HeldDevices/Noticeboard.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.HeldDevices using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/Public/Credits.generated.cs b/Disco.Web/Areas/Public/Views/Public/Credits.generated.cs index 5f509a75..abf0c415 100644 --- a/Disco.Web/Areas/Public/Views/Public/Credits.generated.cs +++ b/Disco.Web/Areas/Public/Views/Public/Credits.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.Public using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/Public/Index.generated.cs b/Disco.Web/Areas/Public/Views/Public/Index.generated.cs index 11e3f46c..163c864a 100644 --- a/Disco.Web/Areas/Public/Views/Public/Index.generated.cs +++ b/Disco.Web/Areas/Public/Views/Public/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.Public using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/Public/Licence.generated.cs b/Disco.Web/Areas/Public/Views/Public/Licence.generated.cs index 20f17049..5af44ce3 100644 --- a/Disco.Web/Areas/Public/Views/Public/Licence.generated.cs +++ b/Disco.Web/Areas/Public/Views/Public/Licence.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.Public using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/UserHeldDevices/Index.generated.cs b/Disco.Web/Areas/Public/Views/UserHeldDevices/Index.generated.cs index 1a74b7dc..a18e5215 100644 --- a/Disco.Web/Areas/Public/Views/UserHeldDevices/Index.generated.cs +++ b/Disco.Web/Areas/Public/Views/UserHeldDevices/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/UserHeldDevices/Noticeboard.generated.cs b/Disco.Web/Areas/Public/Views/UserHeldDevices/Noticeboard.generated.cs index d13768a3..be2e5de5 100644 --- a/Disco.Web/Areas/Public/Views/UserHeldDevices/Noticeboard.generated.cs +++ b/Disco.Web/Areas/Public/Views/UserHeldDevices/Noticeboard.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views.UserHeldDevices using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Areas/Public/Views/_ViewStart.generated.cs b/Disco.Web/Areas/Public/Views/_ViewStart.generated.cs index 9c44caea..1dc334ea 100644 --- a/Disco.Web/Areas/Public/Views/_ViewStart.generated.cs +++ b/Disco.Web/Areas/Public/Views/_ViewStart.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -28,6 +28,7 @@ namespace Disco.Web.Areas.Public.Views using System.Web.WebPages; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/ClientSource/Style/Config.css b/Disco.Web/ClientSource/Style/Config.css index 4a7e1a9c..9639a52c 100644 --- a/Disco.Web/ClientSource/Style/Config.css +++ b/Disco.Web/ClientSource/Style/Config.css @@ -287,6 +287,36 @@ table.deviceProfileTable th.deviceCount { #configurationDeviceProfileShow #displayOrganisationalUnit { margin: 0 0 6px 0; } +.organisationalUnitTree span.fancytree-node { + padding: 1px; + border: none; +} +.organisationalUnitTree span.fancytree-node > span.fancytree-icon { + background: none; + display: inline-block; + font-family: FontAwesome; + font-size: 1.2em; + width: 14px; +} +.organisationalUnitTree span.fancytree-ico-ef > span.fancytree-icon:before { + color: #1e6dab; + font-size: 1em; + content: "\f07c"; +} +.organisationalUnitTree span.fancytree-ico-cf > span.fancytree-icon:before { + color: #1e6dab; + font-size: 1em; + content: "\f07b"; +} +.organisationalUnitTree ul.fancytree-container > li > span > span.fancytree-icon:before { + color: #fa6800; + font-size: 1em; + content: "\f0e8"; +} +.organisationalUnitTree span.fancytree-node.fancytree-selected { + font-style: normal; + background: none; +} #configurationDocumentTemplateExpressionBrowser { padding-right: 275px; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAA6BUlEQVR42u19XZPcxnX2cwDM7FKkZIUph6JykcR2uWzKJdJSyqlKLIl59WU78aXzC3KVm1ynKlf5HclFKjepsuutKBU7ViL5ZSw5CcXQUtmhaFESRZpcLj+X3M/5Avq8FzPANBoNoAE0MLO7fVTUzjQwGACD53w85/RpYmY4ceLkcIrnboETJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOCmVoGyH7//g//6/v/27v4XvB/A8wPcCBIEPogBeQCAi9Hwf5PXR7/nwfIIf9NEPfPi9/pkjK/0PQB6YBYgInkcAPLCIAPIBIrAIQb4HCAFQD/AEfAaE7wGRAMMDEMH3PHAkwOyB2QP5DGYGMYFJgCMGfMAjgAGwEGAhQOSBCPCIIAQAMIRgIPBAACAAQQwIwPd9gAlhxPDAECTgeQARATz9PsGMYHbuRIwoigB48AMPIhJgAjgCmAUCHxAcgEhAsAePp+OiR8AkBIjQ8zwIIQDPAzMgIgGPpufNIMAnsCD4AAACBwwPHogBAkF4Aux5AHkgZviRmH6GGQQCaPa9PjAZjeD5Plj48BCCGfA8QigiCDH9PHMEDjwgihAy0ANhPBYIeoyxEBBjAd9jRBHAFGHMDEwmIA5AxBAeg8MQghns94GxAFaA6cUJQHjwKQB6AqEQCISA8HoIGPB9giAGMWMCIBA+gB68I4yIGR4zViiAEAL02ApoPEbEjMf6j2E0YtBjABMBAI4CCMM+6DEA3vR6jhABCCCC6W8aCAHf9xFFK6CjBMGMY0SIogie1wewAvhDHDtyJGU3I2L0iHDs2LHpfSYPAtPzjqIIe3t72Nraw3jFBwYDRKMRwjCEEALDMETEjBUiCCEwmUwQAeAomj6PAJgZkzDESr8/feamDy48z4PnTe329Lyj5HUQBMm2P/uzPwMz4/Tp039chG9i5kIF8NZPfsIeeckXT/8RyPPh0/Tv9L0H3/NARPB9H0QePJ8Q+AHiq6L51yrvZ+8oc3qaYSraNTOoG9MMTgFuNAajb5kOkWbIdExzOORtUO5n7pjmbEl71Nzv0X9WdxAquY6i79Ef03ws93HX7Jczpr03VHC/5sI8BTCzQIwvIabGg8GJIZH/xaAX8XvNPtPdpspA/gznHE8IgS9/+cvUyAN49PDRFPS+D3+mAHzfnysDZZxovt33PfR6vRqArgJ8PciJTMaqAL+KgmgCfA3UK4G8CvBrjJWATw/8grHaIM8DfhHIGeD5GOvGpmYR0p+pF0azrZmx9DUxJCAKGZQieS1koPIc0Oo/kfd5IVIgz1MCsdfQSAGASAEZSePy40YJyOJ/89vjgF8OcovApwL/5FAC39ziN35GJYeapVOVHW35syz99jSz6DpvM/X52YZp6EHSPqx93UwBSDeJiDQ/xuziSX76aH4BGaAePuAXg7wm8EnzCDcFPlUH6X4EPmniH2vPqPx7xm56HsjjMWm/PEDnjetDEDZWAkE5+CkTm8X/pW8epfGfEz8dVOBXB7kB8AtBXhP4hSA/OMAvjttbAH48JlvhHGVANA015mMZn6AQ9LrxKqCvGAJAcfXlMUp5AdKfGftMDvhlY5VBbgB8sjHmgF9njHPoTVb8eZL2zXP1855FFeQ68LMtBUA6V1/x9omU/WRmgIpuIBUkAJYH+EQFXLwDfufALwX5AoBfarVTNp5Sj0QTV1+3j5xFsMIBSJwflIA/m9pLFEI2FrAHfIKGX2sI8qKUX12QF6X3FgX8vCxBE+BXO6bJWC2Qtw788ufWBMxz4Ntz9bki+WfuAZD8CM1vSBocBMqQIakIoAbwdSBvBvzquf66IG8K/DxvoQnImwK/5LxrgTybvG8OfIJmU+vAL6PuTS17VVc/Ab+hxa/hAVDG1U+drJzyS+cApZ+4O+A3j+91ALRR0GMC8kUDv4ZXUgvkTYGv8xaaAt+Cp0qUJgENyL0yhaAW92S2FREHdhRA1jiQBHLS/JCUihnyUyXLBXw7xTv1QF4F+E0LguwD3xzkVYBfAPLawDcFeXWLryUBDci9IldfC3pVaTQAvzEJKLsAlLpgyhQE+X4wqwQkBIGPfj+QgDwvKqLUzSOQh/R+s78ySJJwhNL7pvaRPJOUD6IdS59DShno9lUfUkp7OHPHJ32PUp4FZcMJKvCGVIVIVG6JTBVfkfUpsyymlodTqKj2sDKgtaGpMdYDlVFcrosUD28A/Bx3UXfv5Uq8+L06nir/lar5gGl1X1zTH1fzxZ9HmTdg3QMgklh+DeGHecrv/oN7ePen78wmCxE8z0MQBHPQzxTIXBHElYOxYom3Q7uP9jPSWNl2khWYfC7IbouVHRnsq92m/ax0Lbpz8ry5AjP9ntQxDa4rJ6as8zquTa+yX6PvU2JddUxHlOW+1h0r57XOFS/aXlannzsPoKCsl5kxGo3wp3/6p3jqqaeseQOB+a6UJgbVqj8Ak/EYt26t4cGDB5kyRSdOnNQTZsZ4PMYTTzyB4XBYSvxxQQhRkwSMyT5KA5+U9CAIvV4PJ0+exObmJq5cuYL79++7X9CJdYmBcNDlwYMH+JM/+RP85m/+ZuK5FIVfcZhgzQPwPIJHNJtTP/3reVO30ovdzdkU4XiGIBHh+PHjuH//PtbW1tzT6sRJBZE95xMnTuCJJ56Ye9QagLP8TxNeNPcAkKr9SZ2ojgSR487f/u3fxne/+11z8umQjbt74e7RYDDApUuXsLGxUagQOAf4SfzfSilwpvw3TTrFWyinJNc9/O7hd/cof/zWrVv41a9+hTAMjTyDRBnIYYAC/IQfsKEAUjwAdFN7SZkKDGs/knvI3T06qPdoMpng0qVLuHv3bqXwgHPAn/EGCniCagpALfBRmn+kwoScG5BX0ugefqcgDuO9uHv3Li5dumRk9TUH0nIAqJkKNJwNKLn6mrkAJNf9KxyA+8EdKNy9mFv9q1ev4te//nUlQlDHAbCBN2ApBJAqAFWLT3mz9EhbA+AefncvDus9evjwIT788EMMBgPUlVT8X+YNGKYDDUuBlZNQSEBSK/ZKbo4DhbsXh+keXb16FVevXoUNycT5edyArRBAtex5WinvvXv4nYI4rOPb29u4fPkytre3G4E+FQJIlp11Vl9VFM1JQErP8JXi/3QmUF+3btKp1D38TkEctPEbN27gypUrsCm6NKDO6vPMHTBxBoJ62ogyIYA+YGg3C+AefnePlm18OBzi8uXLePjwoXXwa0uBVW+g4sxLs7bgcQPQzLx30oYAy5IFcA+/u0ddjq+vr+Pjjz+ul94zJgHyiD8d+G2QgJSdCKwCXAf6ql1P3Li7R/v1Hk0mE1y+fLm1iW/5vRzkfgtVkn91QgBpnrsu7tfFKbob5x5+pyAO0r24f/8+Ll++3K7VzwG/bP7r9gUy8gCIyjWSvJ9JCOAefqcg9vO9CMMQn332GW7evNk62OWuQnPwzy2+ucNf2wNINwNRlYBMAhZ1nan6Q+mUTt6Ch+7hd/eiq3v06NEj/OpXv+qkJ4GcWeO02ZcIwbT3b7kSUB/36yx9Xm+6qiFAUQsr+ZhVPAv3kLt7ZGP82rVruHbtWqfuvppOz4T9Euyrtl80IwEzjSkpUxeQ6qPXIASQvzduMBJbfnnJY7XRonv4nYJoc3xnZwcfffQRdnZ2sCiJ1xRME38atCdpAYshABFp1gXQt9Sue+Nly+95Hnq93qzDsAchBIQQmEwmKSVQFmq4h98piKbjN2/exKeffrpY4LPi3yfWPgf8hm6A4cpA6XhA7QMovyrzAMpufPzZXq+HZ599Fi+88ALee+89XLlyBWEYYjKZJH+jKEoUQ9n3uIffKYiq48PhEFeuXMGjR4+waJkrgTLij+1zABpGIAP8TL1wyU0uWx7J9330ej2cPn0ap0+fxqNHj/A///M/+MlPfoLxeIzRaITJZJIogiiKUn3XF6UInII4GPdobW0N169f7zy9Z0IIFqX9q5YEBIbfrKwRKPMD6VWCVA+gahYg/myypsBMnnzySbzyyit45ZVX8Pbbb+ODDz7A7du3MR6PMR6PE88giqIUSZjnFbiH3ykCnYRhiI8++ggPHjzAMkkmDFCIvyw3YKYBDKYDp+v8SVcQBGjHyuLzon3yegoAwMsvv4yXX34Zly9fxvnz53H58mWMRqNEGcSKQA4N8rwCBwqnIGJ58OBBEmouv2hMP7cUAqhLeaXGlaahuhReFTdct3xSnnz1q1/FV7/6VTx69AgXLlzA22+/nSiC0WiUKIIoihINGnsIThE4BSFb/atXr+LOnTtLCfVsGjDf77eeBlSZQMoohOwikqoSqOL+A0AURQnRZyJPPvkkXn31Vbz66qt466238P777+P27duJMtCFB1ULipyCOJj3aHNzEx9//PHSLzQix/+sof0yJQGGSsCoH4Bs8eWmgFJ70HnXYE0WoMoPFS+oGIYhfvGLX+Af/uEf8Nxzz+GZZ54xulExT/Dhhx/i/PnzuHTpUuIRyOEBESUZhDZLlZ2CWN7xq1ev4tatW0vv7OvTgCgAfUYlNOEA5i2/NJMCNF2Dy3+AvB8kBj8AjMdjAMB//ud/4uLFi/iN3/gN/NEf/RG++c1vYnV1tfTCTp06hVOnTuHRo0d477338NZbb2E0GmE4HCYeQRiGiRKQ04nOOh7sa97d3cXHH3+M3d1d7CeZG1Vl8k/OxCA7HECG7NP0AZgXAWizAFV/KDmlF0URJpMJRqMR/vmf/xlvvvkmnn/+efzBH/wBfu/3fs8oPHjttdfw2muv4d///d/x/vvvY21tLQkNZGUQewWHySM4bArixo0blbryLgPo06E05xB/EgdgOw04XxFI6Q2QpAZ1i4bU+6HiEt8YiDEfMBqNEAQBhsMh3nnnHbz33nt46qmn8PWvfx2vvvqq0c2MeYIPP/wQH3zwAS5cuKDNHsQZBKcIDo6CGI1G+OSTT7C5uYn9KimjqyH+UkWAtjoCqXMBYrJPXgqEkF0XoE4IIKcC5bhH5gXG43GiCHZ3d3Hjxg28+eab+OY3v4nTp08beQVxePCd73wH58+fx5tvvpkiDGXSUE0nuvh6/ymI9fV13LhxY5+k90zJQNbNBUpts8IBxLBPr/5FCQmYQj/0HYHq/IByPUD8OibvwjCE53nwfR+j0QiDwQD/9m//hnPnzuHkyZN47rnnjLyCJ598Eq+//jpef/11/PSnP8XPfvYz3Lp1K+MVxNWGOm/FxdfLey/CMMQnn3ySu+jmfgN+qiegJvbXsAOWSMDE3yetMiCkVwuyuTCIrAjiMdkjmEwmiSIIggB7e3u4ceMGfvzjH+PVV1/F6dOncfLkydIb8eKLL+LFF1/EpUuX8P777+P8+fMYDAYYDofJOcQWxE04Wn4FsbGxgU8//fTAWP3MNWuIP9amBxqTgMgy/UlYkPUCyoBf9wdXZw3GYzqPIAgC9Ho9vPHGG/jxj3+ML3zhC/j617+OF154ofRyn3nmGTzzzDP4zne+g5/97Gd44403MsVEjmhbXgURhiGuXbuGe/fu4SBJogTyiL8CbsBCCKDz8ikdEkDfEKSN+fpqeBCn8GKQxnH8cDhEr9fDL3/5S3z00Uf4p3/6J7z22mt49tlnS72C48eP47vf/S6EEPjBD36AyWSSkJOOaFvO8a2tLXz66acYjUY4iDI1rjnEH2dYQJshgDIDkJBaErxscdC2Hn51nzg0iJWB53kJcRj/+5d/+Re8/fbb+NrXvpbMNCwS3/cRBAE8z9NOMHJE23KMX7t2Dbdv3z6wwGftMuAq8Ve9K6DZ4qCAkuyTXikLhpb9aG09CHLmQAiRAqxsteNQ4aOPPsLNmzdx7tw5/OVf/mXhzT9oKxwdJEWwt7eHTz/9FHt7ezjoQiSl2lluCaLrCgBbpcBSjJ9T9UcyMYhuuwKr4UA8lTgei6cVx7xAr9dDEAT48pe/jDNnzpR6AHEtQtn0YkfAdT++trbWSVfepSMBdeBnHT9oJQ2owD09G2hWIiyHA/kNPW0/CHkLlMSgj933Xq+HlZUVrK6u4vXXXzfODMSkklwY5JY6W/w5jUYjfPbZZ9ja2sJhkXQaML8HYNUgwHAuQLoNWGLvVUXQUQigZgE8z0u6CMXg7/f7CfC/+MUv4rnnnsNLL71kfGM2Njbw7rvv4o033kjqAXStx5wi6Pa7b9++jbW1tdS07kMpEvGXqf63WgqsdgTWMANz11/v/tvKAsgSgz4Gfuzm9/v95N+3vvUtnDlzBk8//bTxff3f//1fXLx4Ef/93/+NwWCAvb09jEajVEWgI+C6VxDxQhy2F93cd2FAGfFXkRQ0CgFItvCSO6CrC7D9IOStQaiL7fv9Pp5++mn8/u//Pr71rW9VusHnzp3DO++8g7W1NQyHw1RTkfhfHvnoFEG7CuLhw4f47LPPDqXVz1tvMw/cVbMBRiFAarZfmgJIj1HzrsDqxTJzYu1jBl+N7VdWVvDSSy/h9OnT+NKXvlTJzf+v//ov/Ou//itGo5G2gYg6F8Ax8d2Nh2GIGzdutLbo5n4kAVMAZ5kUhH6KsJ0QgLLKQI78SUMWorgjUNHDEF9wvDCIHNvHln5lZQVPP/00nn/+eXz729+udEN/+ctf4uc//znOnz+fAF+29vIiJHlxv2Pi2x3f3t7GtWvXDmxRT11FkEkD6vJ9sUKwwQGQtvY/TQJSqkDIbGWgIoIvjvHjxUHifysrK+j3+/jGN76BP/zDP6xk7QHgRz/6ES5evIibN29mZv+p04DVYiNHwHU3fuPGjaXtz7fIMEDuCqQl/hAvGW6xK7DK9JPiGZBcHFBGXBo+CDH4+/0+VldXsbq6iuPHj+Oll17C2bNnceTIkcpu/o9+9KPE0k8mE4zH4wT0cZ5fJvn2e8/A/agI9vb2cP369UNR1FNX8qr85xbfcilwJsWnTgQCsv0BSjoCmawLGAQBjhw5ghdeeAHf+MY38Oyzz1Z2899991384he/0Mb3spuvs/iOgOt2fH19fV/051s6bYDMWsHQvW1GAqKIBJyXByeLhNZ8EOTwIQgCnDlzBn/+539e2c2/cOFCis1XST1d2/FldfUPuoIYj8e4fv06tre3HaANwoD5vYPeF2A5DLBFApJK+MljhExDADRTBDLbX8XN/+EPf5ix9nFLMXV14SI33ymCbr7j7t27WF9fd0U9BuBPxf85xN+8EtDm4qAZay+FBaS6CM1bgskVfnkrA8lu/jvvvNO5m+8URLPPhGGI69ev7+v+fItmAVRvoEobsIocQJoNgAb4BN3S4dWzAGrXn7zP/fCHP0zc/PF4nGr13aWbr27TrYnoFER62+bmJq5fv+6sftMwgHXEXxsdgZJyX5ntl/wAxUUostqmXYHjGXjx2gDAdN22mM0fDoephT50wFeP1/ZDruMy5DDjoE0prmP119bWDkR/vmUIAzJMYEox2OwIRFBXBJdWA1LIQtJb/youd9zVJ27gceHCBbzzzju4dOlSqrlH3A9QdfOLQN/mjES5RFm9fnk6sU7hHXRFsLOzg1//+tcphe6kfgCQAX7MC3ALTUFVL4AUYkAeI2VpsDprA8rW/8KFC/j5z38Oz/MghEhZehlUi1r5Vz5veUJS3I8g/mysrNT1CQ8D17C2tnbg+vMt1PprXH25SBjG9J8xCUjZFmBS2i+lCAo4u6qLggDAcDhMwCSDXV3Ga1EpPNnq93o9HDlyBCsrK+j1eklHonhRk8FgkApvDjoZORgMcOPGDQwGA4dgS3F/hlzPI/6kqkA7IYD8Iun9l9pY7LZUsMqyEtAVFKkLiS7yIY/Pzfd9rK6u4m/+5m/wta99TfuZv/iLv8DVq1dzlyfvgoDravzOnTsHtj/fMsT/rAkFWJv5szodOLXsBzLrA0h1AE1bgqkrAxVZ+UU9/PL5xR5AUd3CysoKfN/XhkUHqajn5s2b2NnZcahtTQnosCT/rZACQNXpwNBNDkp3DMirAaj6QLVt3W2HACr5p0o8o1HuZrQsZcc2jnX//n3cuXPHpfe6JARZdvPnwOfMtsYhAM1r/aWMQGZMAcYiiLmuH37T1KDs3ew3Iq9oWxiGuHnz5qHqz7cUYUCOq99CT0DS0ADKlGCkMwAmD89BqXSLsxNhGBYeQ9dctMtzbWZp9Oe6tbWFmzdvOqvfMSGYnvwjcQAZpWBrcVBKKwR5XFcTAHTTFXiR43HDEpnpLwJC3HAkzmDUmSWptQYVttniPqIowvr6etKfr6xku03ldOisv4b4a3JbjUIAbf2/GgLE+9RcG3A/jsc8RRRFGAwG+Ku/+iusrq5m0oDD4TCZmVikJOqWEdd/kKqP7+7uYm1tDZPJJFPvYGzBOvZgDpg2yAF/2huwxgHouv+QUhpMSh2AujbAfg4BysbjECC26KPRKEUIyiGCPEGpDo+g41V0IC3KwOR5ZmXjURTh3r17ePDggXZ/E3C35cEcJi9AT/xxihiswgZUnA5MJQuDlBNfB0kRxGPyHASZ6Zevv8j1rzN/IrdbrCHgy4Arjw+HQ9y6dQvD4bDU3TdVBHWUQN74YVEM6Xufbf6RpQJbmQ6cLQmelwHkTwlug4BbFCmo7hfHxfLEn7zwp+rDWga4uoDXXYNu/MGDB7h7926lWN9UERTtU0UJHHTFkL6+rKuvXLXlNCA0BKA6CWheGqhdGqytfPciAF/3nPJc7abnUlZwVdeljot64pCm6fmVKYK2lMBBVQpqGpBzswFWFADlgJ8yJKCJFeoSvG0Sam09XHU7KlfdLw80Dx8+xL1795Jy7DrnV0URtaUETJTCvlMIGg6AkUcI2loclJBtDaYhBkFo3A+ga0VgzzVDJeVn8lAW3cu8bVUIQXV7FEVYW1tLuvKaeCtVlEGZN2BDCZTtU/Z+WRWCLhWYtzaQOQVYIQ2YyferNQAVOgItS/xuIxa3AXhTgk+nIKoooKJtOzs7uH37dtKPocl5d0kA1t3P9PPLpBCIaN7sQ2vk5/G/3a7AynqACRugWSPQdHHQ/Qr4ou+Or12ezFQFTOr+TTMAZdtj8vL27dvJBJ664LcV99uI/ata/SpKYxEKIauU0tY+RQ1WPD0DD0BeB1jSCkTK4qBUOjl4vwNeB+iiGLkqmEyOberu6zwFdfve3h5u376NMAwzRJ+Ne24S91clL5sQgHXOe9F1CdlngBTwM7KTAC1yAKmJvxLQM+y/whB2GQKYFrfUsfB1P1M13VaXWCuz/joPTAiBBw8e4NGjR7Vi/Trn2DYB2DT2r6NE1HqPbryA1PrgktXnDDdgpyegUuiT8gekiUCoWAnYdDyv5VheDYIN17bpcYp4BJtpyKJjj0Yj3L17F6PRyNq12CgDbiP2twFyU4+gC+5Angyknw2o8waskoAptyBbHQhzdrqpq19EbtkEfV1PwTT9VOalmPAAZfcs3ndjYyPpymtLIVYh/7qO/ds4lzpicw4HZ1z9OS+Q5gAslQKT5PrLY+m5ANlKYFv9AOoAtCmLXXf/Ku6gabxvIwsQhiFu377d2OrbUgTLRAA29TaqKorGykCy+pn8v2T+TZ2ASh4AMnF+OiTI6whsu0yzakqurodQxuRXdX3VBydv3DSfbgK6ra0tbGxspIp62p6+uwxlwLa9gDq8QzuKoGjyD6sRgR0SMOUPpBwCSo3VuWATV94UxE24AFvHLzv/PMtflvsvu5/qZ6Iowp07dzAcDgGglOWv6n0cJAKwDde/SuVjJUMCXbqPNSGALQ5A5vyzJIAW+EWMcdGsszyLrXuv3ry65J9J5WKdtF7RA1x2H5qEH8A0vVdUymuLE1lUGbBt0Lbt+lv3DJRlwbMdgc3XCQwq4D/t96emAFBjArAKeE2n01Ydrwv4OiFG3bCkyHIJIXDv3r1Kpbxdkn9l578sxT9NXP86yk43Vnyus8k/BbMBYa8hSLbYR18ARLVc4yZknE13vgkobVuBOhZ4OBzi/v37CMOwdeA38QraJACrhgJt/D62jpnHP3EJN2C9KagmEEiWCdKsDl4JNLZcdlPAl4ULdcBuGq/bTinJHYc2NzeTrrxdg99m3N9UCdhMA5pY+K5Cj9S+mjQgy3MDDFRFDQVAacIPaRIw8QwkYMnZAFuVeSbgz8s+NOECbJJzTeNe+XiTyQQPHjzAeDy2dv6149Ka19Ek9m+TALStTOryGWq2KP27IAkFsr6AmT9gXAmoMv+pjIDOBZAuwITUs2X1m/IDTQDfRuZB/h75Ydjc3MTm5mbroUsZ4diWN9BW8c+yu/5F+IlLgTmH+Ev+b3U2ICk1AKmFQtP7mcTUZTPZitJhTWvxbXghbYHM9HvCMMS9e/cwmUxaLXm2FfM3sY6Lnv1nw/VvqsjMfs95KNBCGhCa6cASCVhi2YuUQVFMXgf8trIBTeLeOtOATWV7exubm5va9N6iYv8q1X9F++2H2X+2P1vLwKR6gSq9AaRxttYRKIf5T03/JcosDKqrCiy7QBOLVnVKbhcusYnn00SEELh//z5Go5HRPVt2RdDGhKAuZv+1ERpU4Xxkm5uXBmS1GrBxCAAN2Yd0DYD8Xn04m5bhluXm6yqDNl18m6AcDAaZUt5liO/biPubkGU2QW7i+tsi/ao+R3mNP1im/GyWAmfJPp2CyAe/ziU2AW3VAqGu5gd0ZXmFEHj48CEGg0Fj78IGd1K3nXnZbMaDMPvPVvFPngLKCwO0M/9tcwBEZuArAlQe+NvqmFNUXmyDpa9iOeoAdjQaYWNjI9OfzwaQu/YUlo0AbJNLaIuf0NN+GuKP0xwA21sclJJ+fxl+IDWWXRugDvir5PuLrFWT8MMG4VgVhMyMra2tTH++ZfFK6sT8y0YA1qkDaJvoK7vebAjAuam+1DYbHoAa4ycnleoBmO4IVEaKNbFkTcDQJAXYRoWgLJPJBA8fPsyk99os8LFtodogAOsApysvwLbrb/TbakGvKAarIYABOShPBy7KADSx+m0A31ZNQFMAbm9vY3t7u/I1L0sGoE0C8DAU/5h0ftJOGJLdgNZKgSmf+lP7AOgAXzYBx+Shb2t+gC23v66SCMOwltXvarJVl5ax7djfpuvfheUv9bYKrb354iBmswEzoC5P9+XVAFRx6euA0ibJ1ybjvru7i+3t7dIMSdehSNlnbZUB28gCVA0F2vAC2gwhZBzFK0vLU4FV4g8l/EB9ErAE5KYPURFY25gf0EVlYB2i7+HDhxiPx5Vc/kVmAOrG/E29gSYA78r1b8vyq1kkmlcAaTkAcJulwIbgo4IVgusqgi4sflcs+2g0wubmpnE1Y9fn10bMb+oN1AXOMrn+bSii/N+0yBuAxaagBaSESTxfJRXYBPzLFvOrVn9rawvD4dAoLFrUeXahCA4KAdhWJWDedGAN7Es4ALOWQIHpSVUNAaqAX3Urq5KCTesG2oqXAWA8HmNrawtRFGkbc3aZmlwGRbBsBKCJR2BLqdRdfaiA50uRglOlUO34QdUTKJvgk0cOFoHapFNPkxh/EVOAmRm7u7tJf74q4G8L+F01BKlb+NOULGujcUlbYUBVxTi/n6zp/s2p5YJaCQHywBmX28pdej3Pq1ULUAXEbbL/TfcPwxDb29tJf75FZSaWoSHIopYBL/IC2gwDmtT9F22fe8ak2H0UTAWwsThoCfDreABNYvsuZgM2CRdkq191/sF+IQKXdSmwNmf/LTKsSs1tUV39zOzfltKAJhYgr6tP3X4ATbkAm9aybHts9U0m8LQB/kXwAaYpwUWtAmSzDqDNGX+VflfF1Z//ZVUN2OEA8lx9hW+sDP5FpQJthgnxPoPBAHt7e7UIzINCBHa1CtB+WPWnLSWrc+4Tb6DeymDlCqBobb/5l7Nx6FAF/FXnB3TdMzCKIuzs7CSlvLbDkzbBbzKbsg1wtLEUmA0voO2ef3Wup9h7Zt064XNvgG21BCvQPjCYwFAFFE3mB3TdM3A8HmNnZyex+nXDEdvLmbW1v801AW0TgG16AcvSOizrc2u8cK17YCsEkL0BnUdgoMFsVAPaKBlu4vrH6T25lNdmj0Jb4F+GhiCLXAVo2Vz/JgRl5v6zqgoki1+tJaBBCCDHGboYRFEKVesA6mYAmjYUqaMQJpNJyuo3ISP3cxbANOZvkwC0NeNwmWb8FTUEUUPxFPHHOv/A1nTgHIuPguWuTHsC2JwoZDuvrjLcg8EgWWp7GcG/H9qCd70M+KKtty3vJXd9wEw7cBmzsFcKnIk18tKANUMAm6nAuqDP+0xM9MVdeZvWJdgOSQ5yFmAZ4/c2ZvxVJ+AY2Yl/nOHlrFYC5jH+KaVQMIlhEYqgqdegs/pdWn/bJcx1PtdVGXAXTUCrhgGL4gtMfq9MDUBeYyBrHkAO8KEBvm6B0KqAt2EB64ItiiLs7e1lltpuI0xZ9nZliy4DthlXL2rBzyaf088GlDHJGuB3kQbk8umGNkIAG4CqspLPaDTCYDBI5jTUBfx+7ltgI+ZvUwksYtUfG2GKndmAc1dfigbS2yt8RS0FoMYZebqmahbAZiqw6vJdQojE6pcpr7ZCgabgX0RbcJO4P28fmwRgU4+g61V/GnlwWoxn04DWOACji9Vo7bohQJukoG77ZDIpLeW1af0PGhHYBLDLPvtvUZZfxRFryb1sK6CqswGMSoELH7ACDiAPOLaqAW1Y3b29PUwmEwDpOft1y5W75AKWAfxVQoNlmf233ySlyFQ3gFnjhZtXA9VKA5puK5sK3EZZsCkAwzDE7u5u7nl2af27ygJ00RBkkasALVvxTxsLhJIEfi0emSvRAEEl4JcRfxoXug7BZ4sU1B0nLuop68rbhTJoG/yLbAiyKALQpuu9iM8WhQDTfzkcQO404aYhQKx18tKACgcgT45p2g3H9vyAOL2na7fcRalyV23L2w4L2moC2hUfYeOYbSwCGj+X6t8M6ZrCXJHFt5EGzCn+KZsGXKYEugCdmt4bjUaNXP4urP9+yQJUifvz9ul6BeBlLP4xCTu0nhfnUYGzvsG2OwIxiicGcQ55WNWdt516i6IIw+FQW8rbVXbioBOBXRCAXXkXXaUA69cEcE65b9YbsBYCpCy+pvMoabyBqv3wbIYG8dhkMsFoNMp1pWyRf/uJCDT9bBsVboua/VcXeIs8ZtnvlIr2i7iB1kIAeXuFtQHqWP6qwBJCYDQaIYoiAPr03qKs/34pB25SAly0/yJm/5l85yKWDav1O0Bf/6/FLVqaDVikGIo6AXdRFhy7/Lat/rIUBS2KDLS5JuCyz/6zuUqRjbkMWiTmTvzhZDawdQ5ADQNUpaBfSdg8b99EETBzY6u/LNZ/2YnAtsqAFzH7b9ksfuk911r9+eQf6yFAKfGX42nYygKYKIIoimrH+o4IbP9BX+bZf4vo/FP1euTlwbmA+EufUosdgThHA3AFkNtQBMyMyWSincDTtfu/yJWMDnoWoKvZf7Yq99qw/Nnj5s0GRDsdgVjWBRLwWdUFKO4K3ARc8lhM9OVN4GmiABZh/Ze1HLiLMuC2SbQu2n13EW7pYgBd/b/VtQFVcMvap8jj0IUAeQ992bi6fTKZpHrx23D791NRUJdEYFXyrw4BWAdsTUlG25xAm5WNqXuvrb+bs34tpAFVV5/Vt/PtpCcBbQE/JvrUIiMTYDcF/X6ZHdhmWFBFGXSxDPiirXOX35vXFyCp+tNxA3bSgHmuPmuUAhs9/Cbj6lgYhphMJoV1/Iv2BBbNBXTJB3RVBmxDySy63bet+6yWAuvD/GpFQdU6AmnigfQQGbv/pmNCCEwmEwghSom+LjwBRwS2SwCW7bMsq/50bfnTC4NkXf14pOopBZXArzD+2TQgax/yul18oijKTNs1Abdtq7+sswNtx/hVST9bMfuiQLzMlj/399G9i3sA1DjVCh6AJgzQcQMG4DcBw2g0Sibw1LXyVT2BRYYCbRKBTUOINsuAFzH7r+uYX53ia0dmFX/a40m9A2woAC7xBuR91Bi9aggQu/w23f2DVhTUNRnYdhlw17P/Fj3jr25b8GQ2YBHbz5a7AicNQRSrr0sCgMv7ARQ96GEYJqW8psBvGvfXzQQs4+zALviAtpqBtDX7z5ZFb3PGX6XfMicNyLHVtx4CZNYdLkgDglPti8q12dyqVGX4l9UTaKoM9gsR2IT8qwvORfT8azM8MPV88veVmn8UA7dJCKA5EGtOQgKz53lGLcHi5pxRFOVmDbryBBYRCtgKB7oGf9W4X7e97TRgl5Z/EWQh5y7+M/cErHIArHc6MtuKCoFUbTYej0uLehapCKoqhbas/yLKgbtYE7DN2X9dKb8uZhWmv4cLGIDqHUEqNAXV2XsUFh3p1gkEprP35Fh/WRXAYSYCu1oTsK3Zf/u5+KeMA9ChlFtLAyrEH+W4BbJeylsclJkRhmHqh9EpimX2BGwog6ZcwCLIQFtlwHVifZtewDLX/Vf7DWNXvzrxV5kDSH1JZjag/hRUQAkhChn+/aIAlnl2YFd8QNvVf126110v9NE8BJhzAPkeQRshgBIPsJ4L1D74sdUvAmnbCuCgFwUtggjschWgZWn9vWi+wZTcs+gBQFP1RwXb9A9IGci7UgBdZwKWlQjsigxrqxNwWwtzLIvlz1eyds/DjAMgDeOvaQxiSgLuVwWwbLMD64C/rYYgbS0D3gYQ95M3UFwH0IECmAKfNMQfZ0KB+G9cB3DixAk89dRTrTPzy7DYx35sAJrbc77hg2by+bx9dOMmY1Xem26r8rrOdpNt8WS4tjy9irMB0y91HYHibrwnTpzAX//1X+Po0aNw4sRJPRmNRviP//gPnD9/vpXjV0wDcm4NQDweBAHOnDmDr3zlK+7Xc+KkoayuruL111/HV77yFfzjP/5jmn/rxgPQxPg8pwJlpfD444/jxRdfwuc+9wT29vZAnofAD1LhRJFnoV/moNgjyc2Ccs7c6dwDcynFwlx8dmxwPWrtRKnTxfkXX7Y9/7K5xncq51z+wxj9omz0E5l/Z9EquYanbLIhfTfUephZVQ4zQ7D8HtIy32LG6PN87oyyD+I8/2zsj//Py9ja2uyaA8gSf6wLAhjo9/rwPA+TMITnefCY4ZGXC3wuAQqXbtM8UGUgLdjOZUqBCx5PrgJSzjlm/oNlso0LgF8G3vLP6hFWBFIu1sjpz3KJiigCqcFnucBKcIkFyduuozEScIs5+JkZLKaAn/b3FxBiPpEn7vkP1n0mvU+/vwJhkQyslAbUFv1w2hpz5ifgFoDP1a2zA357wOcSG78I4JeAtx7wy9pu5c3OU0m/5QkxDNOAeiDPi4K4fH7AUgDfTCl0C/xyd94BvwJAGwK/MIQoCgU4/5liRsOC3UUqgJzpwHF6MG9+QKIUioDPJRGaA36nwOca4C0DfqVt+xj4+vvMWPZyg2ppwAwHoCflpqqBSom/pQJ+UYhQF/g1CbxWgV/IS3J9pVAh/j/IwF9WV7+5AlBjfM4qBRn4OU0EHPAd8A22NQF+Q+KvNvCLmnTucwVQ3IZQTwwyZR++/Qv8cqVwEIBfKYY3BH418s7ss0XgrQv8YtxybW9g3ysAbYyfygikJwbFhAfN2cN9Afy68X8psC0Dv5lScMB3wK8TAiig11r8FPBzHtiGwK+b6tt3wLfuDVR317sBvln874C/SAUwmw2InPz/3AfQKwUH/H0OfEPGv1PgNyD+uKQc8LAAv0IIIM0GTN1jzq0IZAaYJG+gE+BXIO86A35x/O+A74DftpTNIKy8OCgXpAF5Rv6l/AJ2wHfAd8Df9xyAsiRoehtlVg7MRdVCgF8j1VeHtV848C1V5hXF/w74hy0ESKy6Zjwh/kjPD1A5eB3wDyjwDRj/urX4DvidegCsjfFzVwxKFQXxPgB+/Tz9fgJ+Xca/boFOXeDXZfzrA/twAr86B1DC+OfOFqwIfLZcmVcW/9cFPtcGb5McvwO+A75d8fKYw6RRZ14PAE6TgpxL9HEmbNB5F4XboFsHTepJWLQt46wUfS6GIRdvy3WA5hOgSrex9qgFjhVnln5W7lBqe2bx9qLPMqfSulmlwaXbtN8JqcmFFvgF22LFkLOdOX9RzPxtJtsPmQeQkyZIBo8eOwqPCJ7vT5t8EE2bfnre9P3sHxHB930QETzPh0c07QgU+MWufpnFL4roLFt8mFj8Iv/GchhgbLVhdDsL4382+N5KxF+1S6pE/FW36OXdnmzJfD4Ag4Xc0UfMFJrUJWh2PYLFzOBIzUCkz1fZJ/6OeBuyPcRYFwJQngL4+7//+4sEkB8E8MjD1Ckg+N5UKcyATzRTEgSC7/kgj+iJJx7/0mBv8MnsBlDaG2CSzmT+mpkiZmB6LTT1SAARhSQBmCTPgWZafV6xLJjml8AUt1+Kv1darYgAQMSdi6YnSkQEIQRi3SgAYsGAZqHG6Q7TG52aCELJ9yVeVar7q/RC2kaFrr60uEoKLLPxUsVAlGV2ad6Canrs9HHlc483J9uScWl74rFxdmEOMQei53k8/w5OtpN0THk7kG2L7fs+M4vUFavrChARs0gvV+/5PmvWJGAg6WjN098/+b3Ziz1iotmlEzyPOP6O2UHgzb5v2huXOFFMBCbyQACi6cMEIoBAzDNwewSOOwVNH/oYyslzMt135plP79e0cZiqAIiASAgdtjNAJwA4e/YsAcD29jaGwyFGoxGFYYiTJ0/S7u4uoiiiY8eO0Wg0wmQyodXVVRqNRhRFEfV6PZpMJhQEgReGIfm+T1EUeZ7nERF5URSR53leFEUeTcUTQngAPCGER0QeEVE8Fm+X/+aNMbMHwGNmb/o7Ecl/pdc0249mGiAeS17THF0kKRRSbiLJYNUpzZz3mQe0bF/LUuc7OjGauhDUcN/M+9lnWRdLzoAaKx6W3ievpXExfWyYiUgQkYhfy2Oz/QQzC2YWnuel/urGAMSvOR6XxgQzs+/7QgghpkqOhRCCfd8XURRxEAQchqHo9Xo8mUzY931eWVnh4XDIvV6PV1ZWsLOzw77v89GjR7G+vs5BEGBlZYVXV1fx+OOPAwDOnTvH9L3vfY/u3btH29vb+MIXvoCdnR06ceIEdnd3aXV1FcPhkPr9Pu3u7qLX6xEACoKAdnd3KQYuABJCeCsrKySEIGb2hBCeEMLzfZ+EEDEQc//GoJbe++p+6mvP82IFQLEiUF/P/slKIAV4ZibJK6CZ9aHYWygBEJW7hLzYZXsOgCQWtrqyYvUYM/DGL0FELAE9pRBmboKQlEgM+tTrqe0SQlIUmdczoEfK+9R23V/P80QURex5nvA8Lx7j0WjEM8XBsSI5evQoh2HIAHgymfDRo0cxHo95dXWVh8Mhjh49ynfu3MGxY8f46tWrePzxxxE888wzBAAnT57E+vo6jh8/js8++4x+93d/V7V+CXgki4/hcEhBEJAMthh8URRREAS5oI8t9+y1LwE3Zd2l1750/MTKy2PSOZCiBPL+6a6zEPBpV7zc0i966a79LLK3VeIZkPK7sOq5QW5mPf8rb9P9i7cJ6Tlh6bWYhQmZ5ypnbUKavqXMs5QOp+Z/wzAUvu+TRNqL+LzDMMTq6iqHYUi9Xg+TySRzX+LXm5ub9Nxzz/HGxgZeeeUVrK+vIzh16hR//vOfpytXruDUqVM4duwYHn/8cT569CgNh0OeTCY4efIkjUYjZmaaaRhaWVnhmfXk2WIgPDvZ2D3yZrEUz7RW7gXObojQrQ0n3xhJc8ca2ouPq4JUduclL4BnN1H+S5KFIMVikPIAsnTuqbEcsFNelsUgLDgs1t30XnCecpVAxir3IIcF8pj0Xk5exMASs20p6694BIn7H1v/2GrP9s28lz8Tu/rxNp31F0KI2UOeWHlm5iAIYu8kxheIiEejEQBwEAQgIl5ZWcH6+jr3ej1eXV3F7u4unzhxAjs7O3j48CFeeumlKQl49uxZBkBnz57FxYsX+Xd+53fQ7/dx79496vf7cVxBOzs7ot/vU6/XE0EQYDwew/d9TCYTbxaXUBAEYub+C8/zvCAIkhDA8zyS3ffYA5i5Rt6Ug/EyLr7k6ieeAwCKxyWvgmTPYfZ9CScw0wsZryDeJpGEufF/rLDU51hWDIoV0j7syn5aEJh4DlVDDMNjWnfRy64pdsfLziHeTzIenN2Fc3kAydVPjIlq9WdgleN/FlN2LgVeFaySosgoBzlEmO2bGp9y0ql9YsMpwjDkGZ44fj/DG/d6PRFFEfr9vgjDEJPJhMfjMR87doxHoxH/1m/9FsbjMT7/+c/zeDzmwWCAb3/72zh37hzOnj3LKQv3/e9/H9/73vcAgC5evIgjR46g3+9TEAQIgoD8WSrQ933a2tqi48ePY0b00WAwoPi153nkeR6Nx+PZW49WVlZoMpnEIKUZIZiAVhlLXPwZj+CpSkSjFEgBvrydZHJQ2pekbYmLJfMFsnIoCRV0fAFpwGJEFtYk77qMNdjivqxDcM4+XDDGyJYkJCCX4nrIJJ+0PQV8aVsKmHL8nwN2luL3hPCTPQPf94Vs1ZUx7vV6YjQa8cwJEP1+n4UQ8XsWQvCRI0eS1xsbG3jiiSc4iiIWQiCKIoRhyGEYIgb+888/DwAs4VxJXWkeonPnztHZs2cBAB9++CFOnTqVesDv3LmDEydO0MbGBh0/fhybm5vkeR7NmEba29sjyfqmXksWOLHKYRh6vV6PZt6EF0URAfBmPEPMLcRATsX9ujHP82iWbUgUjZoZmHkTyfnMshG5nEG87+yYecpBDicoh1AkxV0lNSWYTsOR1uKr401X4zX9vBr+qOOa47A0xsoxWUfcKV/AOpDHbnLsEivbU/9i4kzaN8P4S+z8bC0PkXH9deFAzN7HY7NwWfi+z2EYiiAIeDKZcBAEQvU2ZEUlKyVm5scee4wB8Pb2NoQQ/LnPfY43NjZw/PhxvnPnDp84cSJ1/yScJpY+lxw1dPdMGPDkoV5fX8fJkyfzrGTR66r/vJnSoCAIvLzt8WshRAx0L2cf7eelz2X+SdtS1yFxBCRnF2TXXwk3Sr0JheTSjVGOy2wUOuhc+bzPS+DLuOKasSKrnXLLJRdfjt3VNF4CfiFEAn71n7JNFBB9qVhf+pzI2YcBJKA2OH7ZP5S8BgCWcMWGadHSNCs1JKCopsIoeujrKg0TRQKJSfUaKh9UzCyUego5743DC9NaBEsuf103XX3AUQEIhda9ZJsJCIXytwpwK4HZ4H4ZA7povIzzoZYZaGqoPHK9DM14mVKpq2CKPl/lWFX+lo2ZgL0NPoArvOeKisHkbxmoqnzGFKBcQZGZWudKIC7b1iTNTEuSgiIL+5gAoK5yMR0ny8duw9JTDaDb8gxQAzAm42z52KbWly3cx2YueMMakwDLIU1uFFU4BjUESR3Gnlr4ni6zA9zR71jV+nEL39PmdS+lBNj/0sYP1dR9bjMdRwfsN+n62G4i8AFTAIf5IaNDAnonbT1A7DojOHFyaMVzt8CJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhxYlH+P+B5MeB+eNGIAAAAAElFTkSuQmCC) /*Images/Actions/expressionBrowser256.png*/; diff --git a/Disco.Web/ClientSource/Style/Config.less b/Disco.Web/ClientSource/Style/Config.less index 3902c90c..93e38a34 100644 --- a/Disco.Web/ClientSource/Style/Config.less +++ b/Disco.Web/ClientSource/Style/Config.less @@ -220,6 +220,44 @@ table.deviceProfileTable { } } +.organisationalUnitTree { + span.fancytree-node { + padding: 1px; + border: none; + } + + span.fancytree-node > span.fancytree-icon { + background: none; + display: inline-block; + font-family: FontAwesome; + font-size: 1.2em; + width: 14px; + } + + span.fancytree-ico-ef > span.fancytree-icon:before { + color: @StatusInformation; + font-size: 1em; + content: "\f07c"; + } + + span.fancytree-ico-cf > span.fancytree-icon:before { + color: @StatusInformation; + font-size: 1em; + content: "\f07b"; + } + + ul.fancytree-container > li > span > span.fancytree-icon:before { + color: @StatusAlert; + font-size: 1em; + content: "\f0e8"; + } + + span.fancytree-node.fancytree-selected { + font-style: normal; + background: none; + } +} + #configurationDocumentTemplateExpressionBrowser { padding-right: 275px; background-image: url(data:image/png;base64,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) /*Images/Actions/expressionBrowser256.png*/; @@ -579,6 +617,7 @@ div.logEventsViewport { & > h4 { margin-bottom: 4px; } + #Config_DocumentTemplates_JobSubTypes_Update { margin-top: 4px; } diff --git a/Disco.Web/ClientSource/Style/Config.min.css b/Disco.Web/ClientSource/Style/Config.min.css index d83f7b82..2c4ad16b 100644 --- a/Disco.Web/ClientSource/Style/Config.min.css +++ b/Disco.Web/ClientSource/Style/Config.min.css @@ -1 +1 @@ -.tableData{border:solid 1px #f4f4f4;border-collapse:collapse}.tableData>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}.tableData>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}.tableData>thead>tr>th,.tableData>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}.tableData>tbody>tr:hover>td{background-color:#fefefe}.tableData>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}.tableData>tfoot>tr>th,.tableData>tfoot>tr>td{background-color:#f4f4f4}.tableDataDark{border:solid 1px #d8d8d8;border-collapse:collapse}.tableDataDark td{border:solid 1px #d8d8d8;background-color:#fff}.tableDataDark th{background-color:#eee;border:solid 1px #d8d8d8}.tableDataContainer{background-color:#fff}.tableDataVertical{border:solid 1px #f4f4f4;border-collapse:collapse}.tableDataVertical>tbody>tr:nth-child(odd){background-color:#f4f4f4;margin:0;padding:0}.tableDataVertical>tbody>tr>th.name{width:170px;text-align:right}.tableDataVertical table.sub>tbody>tr:not(:first-child)>th,.tableDataVertical table.sub>tbody>tr:not(:first-child)>td{border-top:1px dashed #aaa}.tableDataVertical table.sub>tbody>tr>th{font-weight:normal;text-align:right}.tableDataVertical table.sub>tbody>tr>th.name{text-align:right}.icon16{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer}.subtleUntilHover{-moz-opacity:.3;opacity:.3}.subtleUntilHover:hover{-moz-opacity:1;opacity:1}#updateAvailableContainer{float:right;border:1px dashed #ddd;background-color:#fff;font-size:.6em;line-height:1em;padding:10px 10px 4px 70px;text-align:right;height:50px}#updateAvailableContainer i{position:absolute;display:block;height:64px;width:64px;vertical-align:middle;margin-left:-70px;font-size:50px;color:#e51400}#updateAvailableContainer a.button{font-size:12px;margin-top:8px}#expressionEditor #expressionEditorExceptionContainer{display:none;border:1px dashed #ff9696;background-color:#ffd8d8;margin:10px 0;padding:10px}#expressionEditor #expressionEditorContainer{border:1px solid #1e6dab;background-color:#f4f4f4;height:100px}.expressionTree span.dynatree-node span.dynatree-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAQCAYAAACm53kpAAAGFklEQVRYw+WVe1BUVRzHvwE+QE0ZLF1Y3gTGSxIl4rk85KHFe0cUiIc8IjNx8gUmLJAFpbIKKJmmCSOi4q48zAe6LqAoioiIMlpOqYWxKCroWFNzO2eXXRdYCBqmf/rNfPece+6598738/ud3wJjHPV8WNwphoSO+L+F3HznWaTVbcGDsYQggkhjJPucWIhcGYYP5xnAKnkh0n1skcGxRobzLGx0MsYmR2MUO5qBMzEAiXhvxmLZU94tq/rJqzUV3q08zL+ei/lt+fC9sRt+N0vh334U/rdOYMEtMRnPqzL/4CxSu46jQFIJgSoI93FfZ7Tmi1FsVoSitWuwhv1Pe51ZcO0+g0BHNkqYH7BVrueXsPlhDYou7cYhrh2OOCzCdhQg7SWAcCYK4X/GIPyPBHBfJIP7fAWCe1chuGc9Qp5kIfhRDgIfbkHQo0IESnaCI74yKPNnkNZ5HPldxLxEiEuSw7i7fgl65BCo+Soc2zkaCHLzZSgLpeM2bBsWAscSM90McID5GTuy41BKzfdexOYn51Ao+R5lvwpR9bsAP65chr0z+TijqgLWw7dtI/zatsoy315GVA2/WyJp1uVyr7k6oOxT5ea7BGgk5u+pMt+N7pCRQtiP/VbUdA1qPLrxNLgFrR/T6wLsMlRscj+bpZAdn+tph5SeBvDi/HGYQjCfjObHtdj+8CRKOwQQ/XIIVyT78GhRFAQ6n6NJ9hKrZeGKF3IZdXDIefO/PQH2l7UQUD8FLnXaZG060Uy8c14PnAYjsJwa6Xb5me86KSv7LpL5riEyT8334FmSCOK8T7D6mrLZjhaEpacjFKzxoTAOWE2W1KhZUgFBj9ETRp+juozmFXQ9D3ksBYBIJgJOe32o+S4xPp1riKqGPdho+BrKKQQWxtXe3IMm8SbcFeWi8zMuJDPsIdLNxg3Z1y2TImUTRk1m/tiEoA78NlDwJOZd6gxg/r6/HAA1WZSCJ5IqCKVlL8BVah4Gvny5TuF0/kDzI6mADcgQfIEcfjOuLXmKZ/H0eTImilGfFI3Yo2SLuhSAV5MfNX9hH1Kpeeh4rHEwQnXjN/hWG69WMBfxk/F0dKpD84W1If4y0oJQ3Q779Xno6AMQG0vMvwKTwHUwWpgJQ/+vpIbJolzSa11XMdhuF5QBKEPoKsc9OioaHwXQVwE7satOlXma+RqhLPseC0gFsNVDYeCQRO/xkCkUQLjtJYTemFa0xcUjsTwa0S1kyzjoe7rRvW5u0Hcxw3d2s2BEr+cYw5VCaNqOFu1x6B0PtWJomyTLvzvRHxFTQ3FPdmUekaAq44MqwE1sTPTGQADKEPp1/T4AcgjUvCHIO0YYPGSVC1FRWI1qfg5y8w6hPGkpEk6kI6MuDnH9ADA8aFApHj54UB3qk0M9zUijM42yRgTDxiSdE6q/ZLYoWTnj0rmhTyH0vfaQD5RBn1MBPfeTJPu10HNpgFVK2EAAcgj9FpQA0JCaj68tQbyIPfD8C0sRFvcBQlnWCAHbdqnsCGyYRyAIjqKyoAKVW2MQ25yJzLoVSGkk82sc8ncO9nz3QQB4PDUsJz0soH0KFt+ZIVU0Yzo0AFPuR4OyLW16jaTpndaDH2l6nPNmcK63gHOjFWanRaoCMCiUAVDT1HwWkwiPYzUDIQxdBTzbLGQLDqCsiGZ9LdY1RCPmeglKLKUb9H1dZUmMipKKIUdZPldWFPPmsABId9eESbCiB8DQuxAGpAL0PA7A85yptAJoD6AVMFoAyuaXX8+Wzu2/ZkZ6FHKRa0ErIRZLmyMR2c4H31ZxU9+n/xE4SP7FSBNHkGgaQm6wwG03RsRNG8Qxs4cHYNsyCd6npsLrog6czr1Osq0Lb9LxXepMiMzhdcGSyBauDXNGBYBKlfkRVoA88pFvswQRt7OQZd/vRh8ARaa5zHjVFfBs7vAAqHldZwuwA21gnjAPs9e64C2eNxy+fBeOeSFw2hGu0EgBKJe/077Gf2t+2DAKfLtfBTCMpkJHGB3wGANkMJbIYWyGB0ANjVajCWp6rM3T0Ji2ifxUQV2rQqHxU4i0KomqoKHZN06sGhrAfxVjbX4M4m/gZza+uQwOHQAAAABJRU5ErkJggg==);background-position-y:0}.expressionTree span.dynatree-node.object span.dynatree-icon{background-position-x:0}.expressionTree span.dynatree-node.parameter span.dynatree-icon{background-position-x:-16px}.expressionTree span.dynatree-node.function span.dynatree-icon{background-position-x:-32px}.expressionTree span.dynatree-node.property span.dynatree-icon{background-position-x:-48px}table.expressionsTable{border:solid 1px #f4f4f4;border-collapse:collapse}table.expressionsTable>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}table.expressionsTable>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}table.expressionsTable>thead>tr>th,table.expressionsTable>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}table.expressionsTable>tbody>tr:hover>td{background-color:#fefefe}table.expressionsTable>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}table.expressionsTable>tfoot>tr>th,table.expressionsTable>tfoot>tr>td{background-color:#f4f4f4}table.expressionsTable td.parseError{background-color:#ffd8d8}#AttachmentType_FilterExpression{width:375px}#deviceComponents{border:solid 1px #f4f4f4;border-collapse:collapse}#deviceComponents>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}#deviceComponents>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}#deviceComponents>thead>tr>th,#deviceComponents>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}#deviceComponents>tbody>tr:hover>td{background-color:#fefefe}#deviceComponents>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}#deviceComponents>tfoot>tr>th,#deviceComponents>tfoot>tr>td{background-color:#f4f4f4}#deviceComponents tr th.actions{width:20px}#deviceComponents tr input.description{width:300px}#deviceComponents tr input.cost{width:75px}#deviceComponents tr i.remove{font-size:1.6em;color:#e51400;cursor:pointer;opacity:.8}#deviceComponents tr i.remove:hover{opacity:1}#deviceComponents tr i.fa-list-alt{color:#1e6dab;font-size:1.6em;cursor:pointer}#deviceComponents tr i.fa-asterisk{color:#fa6800;font-size:1em;left:10px;top:3px;cursor:pointer}#deviceComponents tr input.updating{background-position:right center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAALAPQAAP///zNah+Hm7dng6O7x9DddiTNah1d3nJqtw3+Xs8fS3k5vlm6JqaGzx4KatcrU4FFymDZciHGMq+ru8t/l7Pb3+V9+oeLo7vT2+MTP3LLB0dTc5fHz9gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA)}#organisationAddresses{font-size:.9em}#organisationAddresses tr:not(:last-child){border-bottom:1px dashed #aaa}#organisationAddresses th{padding:2px;font-weight:bold;width:200px}#organisationAddresses td{padding:2px;vertical-align:middle}#organisationAddresses tr:nth-child(even){background-color:#fff}#organisationAddresses i.fa{font-size:1.7em;cursor:pointer}#organisationAddresses i.fa.delete{color:#e51400;opacity:.8}#organisationAddresses i.fa.delete:hover{opacity:1}#organisationAddresses i.fa.edit{color:#1e6dab}ul#loggingEntries{overflow:auto;max-height:230px;padding-left:20px}table.deviceProfileTable th.name{width:300px}table.deviceProfileTable th.type{width:120px}table.deviceProfileTable th.deviceCount{width:120px}#configurationDeviceProfileShow #ComputerNameTemplate{width:300px}#configurationDeviceProfileShow #expressionBrowserAnchor{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACKUlEQVQ4jaWTTU4UURDHf/W6gXFgJlHZKFvEe3gBvYhewXgGTXRpOILhGESGgEuNjB9N/BgCTJjufvXhonsQ176kkqpFVf2q6v8kIvifV77b2wsAU6MsCop/LCEpISIkEUAoioSZYWZczOeUp6en1ZPHT+4FQXgQERDBMrZlHACOpIKcM23bMN3fr0pEcDfub21x9/YdIhwR6QoJWFY8wF2JAHfH3fh8MoUISoGugxnPnj1lZ2eHg/cHTL9MMTdy09K0LVkVy8rsbMZkMukpoRQRRBIAZ2czNjbWWV1bZXY2I6WCpq5pmgY1ZXoypaoqAEQSsSQQ6Tb67es3Xr9+Q103PHy4w+Fkgpoxn1/y8eMn6rq+3v4yp0TkOvpeVaytreHuHB4egggXFxdUVUVZrrKxXmJuLBYLut15PwIwGo1IqTuTSGJlJfj1+xdXV1eMx2PCnTZn3B1VRZY6kJ5gc3MTEenO1Cy4nF9SpILxaIya4maUqrgqdU8QEd0IArgbOStFmVFVNCuqirtjalgYboa5A3KDIAJEGA7XiQiauiZnZTgcXhdwM7RXX1ZlsbgCEUTkL8GD7W3UjMGtAUUqMDMiosf3niqTVbk1GLDUT5nV5Oj4A293d1G1647m3qvOb/hGBLRty9HxB8xM5OWrV49+/vj5wuk07x4CEZ2clxcWUuqclFIgiSIJo9Houdz8zufn56siMgBKoACkNwdcRDIRzWg8bpY5fwBYR4lbku/2TAAAAABJRU5ErkJggg==);text-decoration:none}#configurationDeviceProfileShow #displayComputerNameTemplate{margin:0 0 6px 0}#configurationDeviceProfileShow #displayOrganisationalUnit{margin:0 0 6px 0}#configurationDocumentTemplateExpressionBrowser{padding-right:275px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAA6BUlEQVR42u19XZPcxnX2cwDM7FKkZIUph6JykcR2uWzKJdJSyqlKLIl59WU78aXzC3KVm1ynKlf5HclFKjepsuutKBU7ViL5ZSw5CcXQUtmhaFESRZpcLj+X3M/5Avq8FzPANBoNoAE0MLO7fVTUzjQwGACD53w85/RpYmY4ceLkcIrnboETJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOHEKwIkTJ04BOHHixCkAJ06cOAXgxIkTpwCcOHHiFIATJ06cAnDixIlTAE6cOCmVoGyH7//g//6/v/27v4XvB/A8wPcCBIEPogBeQCAi9Hwf5PXR7/nwfIIf9NEPfPi9/pkjK/0PQB6YBYgInkcAPLCIAPIBIrAIQb4HCAFQD/AEfAaE7wGRAMMDEMH3PHAkwOyB2QP5DGYGMYFJgCMGfMAjgAGwEGAhQOSBCPCIIAQAMIRgIPBAACAAQQwIwPd9gAlhxPDAECTgeQARATz9PsGMYHbuRIwoigB48AMPIhJgAjgCmAUCHxAcgEhAsAePp+OiR8AkBIjQ8zwIIQDPAzMgIgGPpufNIMAnsCD4AAACBwwPHogBAkF4Aux5AHkgZviRmH6GGQQCaPa9PjAZjeD5Plj48BCCGfA8QigiCDH9PHMEDjwgihAy0ANhPBYIeoyxEBBjAd9jRBHAFGHMDEwmIA5AxBAeg8MQghns94GxAFaA6cUJQHjwKQB6AqEQCISA8HoIGPB9giAGMWMCIBA+gB68I4yIGR4zViiAEAL02ApoPEbEjMf6j2E0YtBjABMBAI4CCMM+6DEA3vR6jhABCCCC6W8aCAHf9xFFK6CjBMGMY0SIogie1wewAvhDHDtyJGU3I2L0iHDs2LHpfSYPAtPzjqIIe3t72Nraw3jFBwYDRKMRwjCEEALDMETEjBUiCCEwmUwQAeAomj6PAJgZkzDESr8/feamDy48z4PnTe329Lyj5HUQBMm2P/uzPwMz4/Tp039chG9i5kIF8NZPfsIeeckXT/8RyPPh0/Tv9L0H3/NARPB9H0QePJ8Q+AHiq6L51yrvZ+8oc3qaYSraNTOoG9MMTgFuNAajb5kOkWbIdExzOORtUO5n7pjmbEl71Nzv0X9WdxAquY6i79Ef03ws93HX7Jczpr03VHC/5sI8BTCzQIwvIabGg8GJIZH/xaAX8XvNPtPdpspA/gznHE8IgS9/+cvUyAN49PDRFPS+D3+mAHzfnysDZZxovt33PfR6vRqArgJ8PciJTMaqAL+KgmgCfA3UK4G8CvBrjJWATw/8grHaIM8DfhHIGeD5GOvGpmYR0p+pF0azrZmx9DUxJCAKGZQieS1koPIc0Oo/kfd5IVIgz1MCsdfQSAGASAEZSePy40YJyOJ/89vjgF8OcovApwL/5FAC39ziN35GJYeapVOVHW35syz99jSz6DpvM/X52YZp6EHSPqx93UwBSDeJiDQ/xuziSX76aH4BGaAePuAXg7wm8EnzCDcFPlUH6X4EPmniH2vPqPx7xm56HsjjMWm/PEDnjetDEDZWAkE5+CkTm8X/pW8epfGfEz8dVOBXB7kB8AtBXhP4hSA/OMAvjttbAH48JlvhHGVANA015mMZn6AQ9LrxKqCvGAJAcfXlMUp5AdKfGftMDvhlY5VBbgB8sjHmgF9njHPoTVb8eZL2zXP1855FFeQ68LMtBUA6V1/x9omU/WRmgIpuIBUkAJYH+EQFXLwDfufALwX5AoBfarVTNp5Sj0QTV1+3j5xFsMIBSJwflIA/m9pLFEI2FrAHfIKGX2sI8qKUX12QF6X3FgX8vCxBE+BXO6bJWC2Qtw788ufWBMxz4Ntz9bki+WfuAZD8CM1vSBocBMqQIakIoAbwdSBvBvzquf66IG8K/DxvoQnImwK/5LxrgTybvG8OfIJmU+vAL6PuTS17VVc/Ab+hxa/hAVDG1U+drJzyS+cApZ+4O+A3j+91ALRR0GMC8kUDv4ZXUgvkTYGv8xaaAt+Cp0qUJgENyL0yhaAW92S2FREHdhRA1jiQBHLS/JCUihnyUyXLBXw7xTv1QF4F+E0LguwD3xzkVYBfAPLawDcFeXWLryUBDci9IldfC3pVaTQAvzEJKLsAlLpgyhQE+X4wqwQkBIGPfj+QgDwvKqLUzSOQh/R+s78ySJJwhNL7pvaRPJOUD6IdS59DShno9lUfUkp7OHPHJ32PUp4FZcMJKvCGVIVIVG6JTBVfkfUpsyymlodTqKj2sDKgtaGpMdYDlVFcrosUD28A/Bx3UXfv5Uq8+L06nir/lar5gGl1X1zTH1fzxZ9HmTdg3QMgklh+DeGHecrv/oN7ePen78wmCxE8z0MQBHPQzxTIXBHElYOxYom3Q7uP9jPSWNl2khWYfC7IbouVHRnsq92m/ax0Lbpz8ry5AjP9ntQxDa4rJ6as8zquTa+yX6PvU2JddUxHlOW+1h0r57XOFS/aXlannzsPoKCsl5kxGo3wp3/6p3jqqaeseQOB+a6UJgbVqj8Ak/EYt26t4cGDB5kyRSdOnNQTZsZ4PMYTTzyB4XBYSvxxQQhRkwSMyT5KA5+U9CAIvV4PJ0+exObmJq5cuYL79++7X9CJdYmBcNDlwYMH+JM/+RP85m/+ZuK5FIVfcZhgzQPwPIJHNJtTP/3reVO30ovdzdkU4XiGIBHh+PHjuH//PtbW1tzT6sRJBZE95xMnTuCJJ56Ye9QagLP8TxNeNPcAkKr9SZ2ojgSR487f/u3fxne/+11z8umQjbt74e7RYDDApUuXsLGxUagQOAf4SfzfSilwpvw3TTrFWyinJNc9/O7hd/cof/zWrVv41a9+hTAMjTyDRBnIYYAC/IQfsKEAUjwAdFN7SZkKDGs/knvI3T06qPdoMpng0qVLuHv3bqXwgHPAn/EGCniCagpALfBRmn+kwoScG5BX0ugefqcgDuO9uHv3Li5dumRk9TUH0nIAqJkKNJwNKLn6mrkAJNf9KxyA+8EdKNy9mFv9q1ev4te//nUlQlDHAbCBN2ApBJAqAFWLT3mz9EhbA+AefncvDus9evjwIT788EMMBgPUlVT8X+YNGKYDDUuBlZNQSEBSK/ZKbo4DhbsXh+keXb16FVevXoUNycT5edyArRBAtex5WinvvXv4nYI4rOPb29u4fPkytre3G4E+FQJIlp11Vl9VFM1JQErP8JXi/3QmUF+3btKp1D38TkEctPEbN27gypUrsCm6NKDO6vPMHTBxBoJ62ogyIYA+YGg3C+AefnePlm18OBzi8uXLePjwoXXwa0uBVW+g4sxLs7bgcQPQzLx30oYAy5IFcA+/u0ddjq+vr+Pjjz+ul94zJgHyiD8d+G2QgJSdCKwCXAf6ql1P3Li7R/v1Hk0mE1y+fLm1iW/5vRzkfgtVkn91QgBpnrsu7tfFKbob5x5+pyAO0r24f/8+Ll++3K7VzwG/bP7r9gUy8gCIyjWSvJ9JCOAefqcg9vO9CMMQn332GW7evNk62OWuQnPwzy2+ucNf2wNINwNRlYBMAhZ1nan6Q+mUTt6Ch+7hd/eiq3v06NEj/OpXv+qkJ4GcWeO02ZcIwbT3b7kSUB/36yx9Xm+6qiFAUQsr+ZhVPAv3kLt7ZGP82rVruHbtWqfuvppOz4T9Euyrtl80IwEzjSkpUxeQ6qPXIASQvzduMBJbfnnJY7XRonv4nYJoc3xnZwcfffQRdnZ2sCiJ1xRME38atCdpAYshABFp1gXQt9Sue+Nly+95Hnq93qzDsAchBIQQmEwmKSVQFmq4h98piKbjN2/exKeffrpY4LPi3yfWPgf8hm6A4cpA6XhA7QMovyrzAMpufPzZXq+HZ599Fi+88ALee+89XLlyBWEYYjKZJH+jKEoUQ9n3uIffKYiq48PhEFeuXMGjR4+waJkrgTLij+1zABpGIAP8TL1wyU0uWx7J9330ej2cPn0ap0+fxqNHj/A///M/+MlPfoLxeIzRaITJZJIogiiKUn3XF6UInII4GPdobW0N169f7zy9Z0IIFqX9q5YEBIbfrKwRKPMD6VWCVA+gahYg/myypsBMnnzySbzyyit45ZVX8Pbbb+ODDz7A7du3MR6PMR6PE88giqIUSZjnFbiH3ykCnYRhiI8++ggPHjzAMkkmDFCIvyw3YKYBDKYDp+v8SVcQBGjHyuLzon3yegoAwMsvv4yXX34Zly9fxvnz53H58mWMRqNEGcSKQA4N8rwCBwqnIGJ58OBBEmouv2hMP7cUAqhLeaXGlaahuhReFTdct3xSnnz1q1/FV7/6VTx69AgXLlzA22+/nSiC0WiUKIIoihINGnsIThE4BSFb/atXr+LOnTtLCfVsGjDf77eeBlSZQMoohOwikqoSqOL+A0AURQnRZyJPPvkkXn31Vbz66qt466238P777+P27duJMtCFB1ULipyCOJj3aHNzEx9//PHSLzQix/+sof0yJQGGSsCoH4Bs8eWmgFJ70HnXYE0WoMoPFS+oGIYhfvGLX+Af/uEf8Nxzz+GZZ54xulExT/Dhhx/i/PnzuHTpUuIRyOEBESUZhDZLlZ2CWN7xq1ev4tatW0vv7OvTgCgAfUYlNOEA5i2/NJMCNF2Dy3+AvB8kBj8AjMdjAMB//ud/4uLFi/iN3/gN/NEf/RG++c1vYnV1tfTCTp06hVOnTuHRo0d477338NZbb2E0GmE4HCYeQRiGiRKQ04nOOh7sa97d3cXHH3+M3d1d7CeZG1Vl8k/OxCA7HECG7NP0AZgXAWizAFV/KDmlF0URJpMJRqMR/vmf/xlvvvkmnn/+efzBH/wBfu/3fs8oPHjttdfw2muv4d///d/x/vvvY21tLQkNZGUQewWHySM4bArixo0blbryLgPo06E05xB/EgdgOw04XxFI6Q2QpAZ1i4bU+6HiEt8YiDEfMBqNEAQBhsMh3nnnHbz33nt46qmn8PWvfx2vvvqq0c2MeYIPP/wQH3zwAS5cuKDNHsQZBKcIDo6CGI1G+OSTT7C5uYn9KimjqyH+UkWAtjoCqXMBYrJPXgqEkF0XoE4IIKcC5bhH5gXG43GiCHZ3d3Hjxg28+eab+OY3v4nTp08beQVxePCd73wH58+fx5tvvpkiDGXSUE0nuvh6/ymI9fV13LhxY5+k90zJQNbNBUpts8IBxLBPr/5FCQmYQj/0HYHq/IByPUD8OibvwjCE53nwfR+j0QiDwQD/9m//hnPnzuHkyZN47rnnjLyCJ598Eq+//jpef/11/PSnP8XPfvYz3Lp1K+MVxNWGOm/FxdfLey/CMMQnn3ySu+jmfgN+qiegJvbXsAOWSMDE3yetMiCkVwuyuTCIrAjiMdkjmEwmiSIIggB7e3u4ceMGfvzjH+PVV1/F6dOncfLkydIb8eKLL+LFF1/EpUuX8P777+P8+fMYDAYYDofJOcQWxE04Wn4FsbGxgU8//fTAWP3MNWuIP9amBxqTgMgy/UlYkPUCyoBf9wdXZw3GYzqPIAgC9Ho9vPHGG/jxj3+ML3zhC/j617+OF154ofRyn3nmGTzzzDP4zne+g5/97Gd44403MsVEjmhbXgURhiGuXbuGe/fu4SBJogTyiL8CbsBCCKDz8ikdEkDfEKSN+fpqeBCn8GKQxnH8cDhEr9fDL3/5S3z00Uf4p3/6J7z22mt49tlnS72C48eP47vf/S6EEPjBD36AyWSSkJOOaFvO8a2tLXz66acYjUY4iDI1rjnEH2dYQJshgDIDkJBaErxscdC2Hn51nzg0iJWB53kJcRj/+5d/+Re8/fbb+NrXvpbMNCwS3/cRBAE8z9NOMHJE23KMX7t2Dbdv3z6wwGftMuAq8Ve9K6DZ4qCAkuyTXikLhpb9aG09CHLmQAiRAqxsteNQ4aOPPsLNmzdx7tw5/OVf/mXhzT9oKxwdJEWwt7eHTz/9FHt7ezjoQiSl2lluCaLrCgBbpcBSjJ9T9UcyMYhuuwKr4UA8lTgei6cVx7xAr9dDEAT48pe/jDNnzpR6AHEtQtn0YkfAdT++trbWSVfepSMBdeBnHT9oJQ2owD09G2hWIiyHA/kNPW0/CHkLlMSgj933Xq+HlZUVrK6u4vXXXzfODMSkklwY5JY6W/w5jUYjfPbZZ9ja2sJhkXQaML8HYNUgwHAuQLoNWGLvVUXQUQigZgE8z0u6CMXg7/f7CfC/+MUv4rnnnsNLL71kfGM2Njbw7rvv4o033kjqAXStx5wi6Pa7b9++jbW1tdS07kMpEvGXqf63WgqsdgTWMANz11/v/tvKAsgSgz4Gfuzm9/v95N+3vvUtnDlzBk8//bTxff3f//1fXLx4Ef/93/+NwWCAvb09jEajVEWgI+C6VxDxQhy2F93cd2FAGfFXkRQ0CgFItvCSO6CrC7D9IOStQaiL7fv9Pp5++mn8/u//Pr71rW9VusHnzp3DO++8g7W1NQyHw1RTkfhfHvnoFEG7CuLhw4f47LPPDqXVz1tvMw/cVbMBRiFAarZfmgJIj1HzrsDqxTJzYu1jBl+N7VdWVvDSSy/h9OnT+NKXvlTJzf+v//ov/Ou//itGo5G2gYg6F8Ax8d2Nh2GIGzdutLbo5n4kAVMAZ5kUhH6KsJ0QgLLKQI78SUMWorgjUNHDEF9wvDCIHNvHln5lZQVPP/00nn/+eXz729+udEN/+ctf4uc//znOnz+fAF+29vIiJHlxv2Pi2x3f3t7GtWvXDmxRT11FkEkD6vJ9sUKwwQGQtvY/TQJSqkDIbGWgIoIvjvHjxUHifysrK+j3+/jGN76BP/zDP6xk7QHgRz/6ES5evIibN29mZv+p04DVYiNHwHU3fuPGjaXtz7fIMEDuCqQl/hAvGW6xK7DK9JPiGZBcHFBGXBo+CDH4+/0+VldXsbq6iuPHj+Oll17C2bNnceTIkcpu/o9+9KPE0k8mE4zH4wT0cZ5fJvn2e8/A/agI9vb2cP369UNR1FNX8qr85xbfcilwJsWnTgQCsv0BSjoCmawLGAQBjhw5ghdeeAHf+MY38Oyzz1Z2899991384he/0Mb3spuvs/iOgOt2fH19fV/051s6bYDMWsHQvW1GAqKIBJyXByeLhNZ8EOTwIQgCnDlzBn/+539e2c2/cOFCis1XST1d2/FldfUPuoIYj8e4fv06tre3HaANwoD5vYPeF2A5DLBFApJK+MljhExDADRTBDLbX8XN/+EPf5ix9nFLMXV14SI33ymCbr7j7t27WF9fd0U9BuBPxf85xN+8EtDm4qAZay+FBaS6CM1bgskVfnkrA8lu/jvvvNO5m+8URLPPhGGI69ev7+v+fItmAVRvoEobsIocQJoNgAb4BN3S4dWzAGrXn7zP/fCHP0zc/PF4nGr13aWbr27TrYnoFER62+bmJq5fv+6sftMwgHXEXxsdgZJyX5ntl/wAxUUostqmXYHjGXjx2gDAdN22mM0fDoephT50wFeP1/ZDruMy5DDjoE0prmP119bWDkR/vmUIAzJMYEox2OwIRFBXBJdWA1LIQtJb/youd9zVJ27gceHCBbzzzju4dOlSqrlH3A9QdfOLQN/mjES5RFm9fnk6sU7hHXRFsLOzg1//+tcphe6kfgCQAX7MC3ALTUFVL4AUYkAeI2VpsDprA8rW/8KFC/j5z38Oz/MghEhZehlUi1r5Vz5veUJS3I8g/mysrNT1CQ8D17C2tnbg+vMt1PprXH25SBjG9J8xCUjZFmBS2i+lCAo4u6qLggDAcDhMwCSDXV3Ga1EpPNnq93o9HDlyBCsrK+j1eklHonhRk8FgkApvDjoZORgMcOPGDQwGA4dgS3F/hlzPI/6kqkA7IYD8Iun9l9pY7LZUsMqyEtAVFKkLiS7yIY/Pzfd9rK6u4m/+5m/wta99TfuZv/iLv8DVq1dzlyfvgoDravzOnTsHtj/fMsT/rAkFWJv5szodOLXsBzLrA0h1AE1bgqkrAxVZ+UU9/PL5xR5AUd3CysoKfN/XhkUHqajn5s2b2NnZcahtTQnosCT/rZACQNXpwNBNDkp3DMirAaj6QLVt3W2HACr5p0o8o1HuZrQsZcc2jnX//n3cuXPHpfe6JARZdvPnwOfMtsYhAM1r/aWMQGZMAcYiiLmuH37T1KDs3ew3Iq9oWxiGuHnz5qHqz7cUYUCOq99CT0DS0ADKlGCkMwAmD89BqXSLsxNhGBYeQ9dctMtzbWZp9Oe6tbWFmzdvOqvfMSGYnvwjcQAZpWBrcVBKKwR5XFcTAHTTFXiR43HDEpnpLwJC3HAkzmDUmSWptQYVttniPqIowvr6etKfr6xku03ldOisv4b4a3JbjUIAbf2/GgLE+9RcG3A/jsc8RRRFGAwG+Ku/+iusrq5m0oDD4TCZmVikJOqWEdd/kKqP7+7uYm1tDZPJJFPvYGzBOvZgDpg2yAF/2huwxgHouv+QUhpMSh2AujbAfg4BysbjECC26KPRKEUIyiGCPEGpDo+g41V0IC3KwOR5ZmXjURTh3r17ePDggXZ/E3C35cEcJi9AT/xxihiswgZUnA5MJQuDlBNfB0kRxGPyHASZ6Zevv8j1rzN/IrdbrCHgy4Arjw+HQ9y6dQvD4bDU3TdVBHWUQN74YVEM6Xufbf6RpQJbmQ6cLQmelwHkTwlug4BbFCmo7hfHxfLEn7zwp+rDWga4uoDXXYNu/MGDB7h7926lWN9UERTtU0UJHHTFkL6+rKuvXLXlNCA0BKA6CWheGqhdGqytfPciAF/3nPJc7abnUlZwVdeljot64pCm6fmVKYK2lMBBVQpqGpBzswFWFADlgJ8yJKCJFeoSvG0Sam09XHU7KlfdLw80Dx8+xL1795Jy7DrnV0URtaUETJTCvlMIGg6AkUcI2loclJBtDaYhBkFo3A+ga0VgzzVDJeVn8lAW3cu8bVUIQXV7FEVYW1tLuvKaeCtVlEGZN2BDCZTtU/Z+WRWCLhWYtzaQOQVYIQ2YyferNQAVOgItS/xuIxa3AXhTgk+nIKoooKJtOzs7uH37dtKPocl5d0kA1t3P9PPLpBCIaN7sQ2vk5/G/3a7AynqACRugWSPQdHHQ/Qr4ou+Or12ezFQFTOr+TTMAZdtj8vL27dvJBJ664LcV99uI/ata/SpKYxEKIauU0tY+RQ1WPD0DD0BeB1jSCkTK4qBUOjl4vwNeB+iiGLkqmEyOberu6zwFdfve3h5u376NMAwzRJ+Ne24S91clL5sQgHXOe9F1CdlngBTwM7KTAC1yAKmJvxLQM+y/whB2GQKYFrfUsfB1P1M13VaXWCuz/joPTAiBBw8e4NGjR7Vi/Trn2DYB2DT2r6NE1HqPbryA1PrgktXnDDdgpyegUuiT8gekiUCoWAnYdDyv5VheDYIN17bpcYp4BJtpyKJjj0Yj3L17F6PRyNq12CgDbiP2twFyU4+gC+5Angyknw2o8waskoAptyBbHQhzdrqpq19EbtkEfV1PwTT9VOalmPAAZfcs3ndjYyPpymtLIVYh/7qO/ds4lzpicw4HZ1z9OS+Q5gAslQKT5PrLY+m5ANlKYFv9AOoAtCmLXXf/Ku6gabxvIwsQhiFu377d2OrbUgTLRAA29TaqKorGykCy+pn8v2T+TZ2ASh4AMnF+OiTI6whsu0yzakqurodQxuRXdX3VBydv3DSfbgK6ra0tbGxspIp62p6+uwxlwLa9gDq8QzuKoGjyD6sRgR0SMOUPpBwCSo3VuWATV94UxE24AFvHLzv/PMtflvsvu5/qZ6Iowp07dzAcDgGglOWv6n0cJAKwDde/SuVjJUMCXbqPNSGALQ5A5vyzJIAW+EWMcdGsszyLrXuv3ry65J9J5WKdtF7RA1x2H5qEH8A0vVdUymuLE1lUGbBt0Lbt+lv3DJRlwbMdgc3XCQwq4D/t96emAFBjArAKeE2n01Ydrwv4OiFG3bCkyHIJIXDv3r1Kpbxdkn9l578sxT9NXP86yk43Vnyus8k/BbMBYa8hSLbYR18ARLVc4yZknE13vgkobVuBOhZ4OBzi/v37CMOwdeA38QraJACrhgJt/D62jpnHP3EJN2C9KagmEEiWCdKsDl4JNLZcdlPAl4ULdcBuGq/bTinJHYc2NzeTrrxdg99m3N9UCdhMA5pY+K5Cj9S+mjQgy3MDDFRFDQVAacIPaRIw8QwkYMnZAFuVeSbgz8s+NOECbJJzTeNe+XiTyQQPHjzAeDy2dv6149Ka19Ek9m+TALStTOryGWq2KP27IAkFsr6AmT9gXAmoMv+pjIDOBZAuwITUs2X1m/IDTQDfRuZB/h75Ydjc3MTm5mbroUsZ4diWN9BW8c+yu/5F+IlLgTmH+Ev+b3U2ICk1AKmFQtP7mcTUZTPZitJhTWvxbXghbYHM9HvCMMS9e/cwmUxaLXm2FfM3sY6Lnv1nw/VvqsjMfs95KNBCGhCa6cASCVhi2YuUQVFMXgf8trIBTeLeOtOATWV7exubm5va9N6iYv8q1X9F++2H2X+2P1vLwKR6gSq9AaRxttYRKIf5T03/JcosDKqrCiy7QBOLVnVKbhcusYnn00SEELh//z5Go5HRPVt2RdDGhKAuZv+1ERpU4Xxkm5uXBmS1GrBxCAAN2Yd0DYD8Xn04m5bhluXm6yqDNl18m6AcDAaZUt5liO/biPubkGU2QW7i+tsi/ao+R3mNP1im/GyWAmfJPp2CyAe/ziU2AW3VAqGu5gd0ZXmFEHj48CEGg0Fj78IGd1K3nXnZbMaDMPvPVvFPngLKCwO0M/9tcwBEZuArAlQe+NvqmFNUXmyDpa9iOeoAdjQaYWNjI9OfzwaQu/YUlo0AbJNLaIuf0NN+GuKP0xwA21sclJJ+fxl+IDWWXRugDvir5PuLrFWT8MMG4VgVhMyMra2tTH++ZfFK6sT8y0YA1qkDaJvoK7vebAjAuam+1DYbHoAa4ycnleoBmO4IVEaKNbFkTcDQJAXYRoWgLJPJBA8fPsyk99os8LFtodogAOsApysvwLbrb/TbakGvKAarIYABOShPBy7KADSx+m0A31ZNQFMAbm9vY3t7u/I1L0sGoE0C8DAU/5h0ftJOGJLdgNZKgSmf+lP7AOgAXzYBx+Shb2t+gC23v66SCMOwltXvarJVl5ax7djfpuvfheUv9bYKrb354iBmswEzoC5P9+XVAFRx6euA0ibJ1ybjvru7i+3t7dIMSdehSNlnbZUB28gCVA0F2vAC2gwhZBzFK0vLU4FV4g8l/EB9ErAE5KYPURFY25gf0EVlYB2i7+HDhxiPx5Vc/kVmAOrG/E29gSYA78r1b8vyq1kkmlcAaTkAcJulwIbgo4IVgusqgi4sflcs+2g0wubmpnE1Y9fn10bMb+oN1AXOMrn+bSii/N+0yBuAxaagBaSESTxfJRXYBPzLFvOrVn9rawvD4dAoLFrUeXahCA4KAdhWJWDedGAN7Es4ALOWQIHpSVUNAaqAX3Urq5KCTesG2oqXAWA8HmNrawtRFGkbc3aZmlwGRbBsBKCJR2BLqdRdfaiA50uRglOlUO34QdUTKJvgk0cOFoHapFNPkxh/EVOAmRm7u7tJf74q4G8L+F01BKlb+NOULGujcUlbYUBVxTi/n6zp/s2p5YJaCQHywBmX28pdej3Pq1ULUAXEbbL/TfcPwxDb29tJf75FZSaWoSHIopYBL/IC2gwDmtT9F22fe8ak2H0UTAWwsThoCfDreABNYvsuZgM2CRdkq191/sF+IQKXdSmwNmf/LTKsSs1tUV39zOzfltKAJhYgr6tP3X4ATbkAm9aybHts9U0m8LQB/kXwAaYpwUWtAmSzDqDNGX+VflfF1Z//ZVUN2OEA8lx9hW+sDP5FpQJthgnxPoPBAHt7e7UIzINCBHa1CtB+WPWnLSWrc+4Tb6DeymDlCqBobb/5l7Nx6FAF/FXnB3TdMzCKIuzs7CSlvLbDkzbBbzKbsg1wtLEUmA0voO2ef3Wup9h7Zt064XNvgG21BCvQPjCYwFAFFE3mB3TdM3A8HmNnZyex+nXDEdvLmbW1v801AW0TgG16AcvSOizrc2u8cK17YCsEkL0BnUdgoMFsVAPaKBlu4vrH6T25lNdmj0Jb4F+GhiCLXAVo2Vz/JgRl5v6zqgoki1+tJaBBCCDHGboYRFEKVesA6mYAmjYUqaMQJpNJyuo3ISP3cxbANOZvkwC0NeNwmWb8FTUEUUPxFPHHOv/A1nTgHIuPguWuTHsC2JwoZDuvrjLcg8EgWWp7GcG/H9qCd70M+KKtty3vJXd9wEw7cBmzsFcKnIk18tKANUMAm6nAuqDP+0xM9MVdeZvWJdgOSQ5yFmAZ4/c2ZvxVJ+AY2Yl/nOHlrFYC5jH+KaVQMIlhEYqgqdegs/pdWn/bJcx1PtdVGXAXTUCrhgGL4gtMfq9MDUBeYyBrHkAO8KEBvm6B0KqAt2EB64ItiiLs7e1lltpuI0xZ9nZliy4DthlXL2rBzyaf088GlDHJGuB3kQbk8umGNkIAG4CqspLPaDTCYDBI5jTUBfx+7ltgI+ZvUwksYtUfG2GKndmAc1dfigbS2yt8RS0FoMYZebqmahbAZiqw6vJdQojE6pcpr7ZCgabgX0RbcJO4P28fmwRgU4+g61V/GnlwWoxn04DWOACji9Vo7bohQJukoG77ZDIpLeW1af0PGhHYBLDLPvtvUZZfxRFryb1sK6CqswGMSoELH7ACDiAPOLaqAW1Y3b29PUwmEwDpOft1y5W75AKWAfxVQoNlmf233ySlyFQ3gFnjhZtXA9VKA5puK5sK3EZZsCkAwzDE7u5u7nl2af27ygJ00RBkkasALVvxTxsLhJIEfi0emSvRAEEl4JcRfxoXug7BZ4sU1B0nLuop68rbhTJoG/yLbAiyKALQpuu9iM8WhQDTfzkcQO404aYhQKx18tKACgcgT45p2g3H9vyAOL2na7fcRalyV23L2w4L2moC2hUfYeOYbSwCGj+X6t8M6ZrCXJHFt5EGzCn+KZsGXKYEugCdmt4bjUaNXP4urP9+yQJUifvz9ul6BeBlLP4xCTu0nhfnUYGzvsG2OwIxiicGcQ55WNWdt516i6IIw+FQW8rbVXbioBOBXRCAXXkXXaUA69cEcE65b9YbsBYCpCy+pvMoabyBqv3wbIYG8dhkMsFoNMp1pWyRf/uJCDT9bBsVboua/VcXeIs8ZtnvlIr2i7iB1kIAeXuFtQHqWP6qwBJCYDQaIYoiAPr03qKs/34pB25SAly0/yJm/5l85yKWDav1O0Bf/6/FLVqaDVikGIo6AXdRFhy7/Lat/rIUBS2KDLS5JuCyz/6zuUqRjbkMWiTmTvzhZDawdQ5ADQNUpaBfSdg8b99EETBzY6u/LNZ/2YnAtsqAFzH7b9ksfuk911r9+eQf6yFAKfGX42nYygKYKIIoimrH+o4IbP9BX+bZf4vo/FP1euTlwbmA+EufUosdgThHA3AFkNtQBMyMyWSincDTtfu/yJWMDnoWoKvZf7Yq99qw/Nnj5s0GRDsdgVjWBRLwWdUFKO4K3ARc8lhM9OVN4GmiABZh/Ze1HLiLMuC2SbQu2n13EW7pYgBd/b/VtQFVcMvap8jj0IUAeQ992bi6fTKZpHrx23D791NRUJdEYFXyrw4BWAdsTUlG25xAm5WNqXuvrb+bs34tpAFVV5/Vt/PtpCcBbQE/JvrUIiMTYDcF/X6ZHdhmWFBFGXSxDPiirXOX35vXFyCp+tNxA3bSgHmuPmuUAhs9/Cbj6lgYhphMJoV1/Iv2BBbNBXTJB3RVBmxDySy63bet+6yWAuvD/GpFQdU6AmnigfQQGbv/pmNCCEwmEwghSom+LjwBRwS2SwCW7bMsq/50bfnTC4NkXf14pOopBZXArzD+2TQgax/yul18oijKTNs1Abdtq7+sswNtx/hVST9bMfuiQLzMlj/399G9i3sA1DjVCh6AJgzQcQMG4DcBw2g0Sibw1LXyVT2BRYYCbRKBTUOINsuAFzH7r+uYX53ia0dmFX/a40m9A2woAC7xBuR91Bi9aggQu/w23f2DVhTUNRnYdhlw17P/Fj3jr25b8GQ2YBHbz5a7AicNQRSrr0sCgMv7ARQ96GEYJqW8psBvGvfXzQQs4+zALviAtpqBtDX7z5ZFb3PGX6XfMicNyLHVtx4CZNYdLkgDglPti8q12dyqVGX4l9UTaKoM9gsR2IT8qwvORfT8azM8MPV88veVmn8UA7dJCKA5EGtOQgKz53lGLcHi5pxRFOVmDbryBBYRCtgKB7oGf9W4X7e97TRgl5Z/EWQh5y7+M/cErHIArHc6MtuKCoFUbTYej0uLehapCKoqhbas/yLKgbtYE7DN2X9dKb8uZhWmv4cLGIDqHUEqNAXV2XsUFh3p1gkEprP35Fh/WRXAYSYCu1oTsK3Zf/u5+KeMA9ChlFtLAyrEH+W4BbJeylsclJkRhmHqh9EpimX2BGwog6ZcwCLIQFtlwHVifZtewDLX/Vf7DWNXvzrxV5kDSH1JZjag/hRUQAkhChn+/aIAlnl2YFd8QNvVf126110v9NE8BJhzAPkeQRshgBIPsJ4L1D74sdUvAmnbCuCgFwUtggjschWgZWn9vWi+wZTcs+gBQFP1RwXb9A9IGci7UgBdZwKWlQjsigxrqxNwWwtzLIvlz1eyds/DjAMgDeOvaQxiSgLuVwWwbLMD64C/rYYgbS0D3gYQ95M3UFwH0IECmAKfNMQfZ0KB+G9cB3DixAk89dRTrTPzy7DYx35sAJrbc77hg2by+bx9dOMmY1Xem26r8rrOdpNt8WS4tjy9irMB0y91HYHibrwnTpzAX//1X+Po0aNw4sRJPRmNRviP//gPnD9/vpXjV0wDcm4NQDweBAHOnDmDr3zlK+7Xc+KkoayuruL111/HV77yFfzjP/5jmn/rxgPQxPg8pwJlpfD444/jxRdfwuc+9wT29vZAnofAD1LhRJFnoV/moNgjyc2Ccs7c6dwDcynFwlx8dmxwPWrtRKnTxfkXX7Y9/7K5xncq51z+wxj9omz0E5l/Z9EquYanbLIhfTfUephZVQ4zQ7D8HtIy32LG6PN87oyyD+I8/2zsj//Py9ja2uyaA8gSf6wLAhjo9/rwPA+TMITnefCY4ZGXC3wuAQqXbtM8UGUgLdjOZUqBCx5PrgJSzjlm/oNlso0LgF8G3vLP6hFWBFIu1sjpz3KJiigCqcFnucBKcIkFyduuozEScIs5+JkZLKaAn/b3FxBiPpEn7vkP1n0mvU+/vwJhkQyslAbUFv1w2hpz5ifgFoDP1a2zA357wOcSG78I4JeAtx7wy9pu5c3OU0m/5QkxDNOAeiDPi4K4fH7AUgDfTCl0C/xyd94BvwJAGwK/MIQoCgU4/5liRsOC3UUqgJzpwHF6MG9+QKIUioDPJRGaA36nwOca4C0DfqVt+xj4+vvMWPZyg2ppwAwHoCflpqqBSom/pQJ+UYhQF/g1CbxWgV/IS3J9pVAh/j/IwF9WV7+5AlBjfM4qBRn4OU0EHPAd8A22NQF+Q+KvNvCLmnTucwVQ3IZQTwwyZR++/Qv8cqVwEIBfKYY3BH418s7ss0XgrQv8YtxybW9g3ysAbYyfygikJwbFhAfN2cN9Afy68X8psC0Dv5lScMB3wK8TAiig11r8FPBzHtiGwK+b6tt3wLfuDVR317sBvln874C/SAUwmw2InPz/3AfQKwUH/H0OfEPGv1PgNyD+uKQc8LAAv0IIIM0GTN1jzq0IZAaYJG+gE+BXIO86A35x/O+A74DftpTNIKy8OCgXpAF5Rv6l/AJ2wHfAd8Df9xyAsiRoehtlVg7MRdVCgF8j1VeHtV848C1V5hXF/w74hy0ESKy6Zjwh/kjPD1A5eB3wDyjwDRj/urX4DvidegCsjfFzVwxKFQXxPgB+/Tz9fgJ+Xca/boFOXeDXZfzrA/twAr86B1DC+OfOFqwIfLZcmVcW/9cFPtcGb5McvwO+A75d8fKYw6RRZ14PAE6TgpxL9HEmbNB5F4XboFsHTepJWLQt46wUfS6GIRdvy3WA5hOgSrex9qgFjhVnln5W7lBqe2bx9qLPMqfSulmlwaXbtN8JqcmFFvgF22LFkLOdOX9RzPxtJtsPmQeQkyZIBo8eOwqPCJ7vT5t8EE2bfnre9P3sHxHB930QETzPh0c07QgU+MWufpnFL4roLFt8mFj8Iv/GchhgbLVhdDsL4382+N5KxF+1S6pE/FW36OXdnmzJfD4Ag4Xc0UfMFJrUJWh2PYLFzOBIzUCkz1fZJ/6OeBuyPcRYFwJQngL4+7//+4sEkB8E8MjD1Ckg+N5UKcyATzRTEgSC7/kgj+iJJx7/0mBv8MnsBlDaG2CSzmT+mpkiZmB6LTT1SAARhSQBmCTPgWZafV6xLJjml8AUt1+Kv1darYgAQMSdi6YnSkQEIQRi3SgAYsGAZqHG6Q7TG52aCELJ9yVeVar7q/RC2kaFrr60uEoKLLPxUsVAlGV2ad6Canrs9HHlc483J9uScWl74rFxdmEOMQei53k8/w5OtpN0THk7kG2L7fs+M4vUFavrChARs0gvV+/5PmvWJGAg6WjN098/+b3Ziz1iotmlEzyPOP6O2UHgzb5v2huXOFFMBCbyQACi6cMEIoBAzDNwewSOOwVNH/oYyslzMt135plP79e0cZiqAIiASAgdtjNAJwA4e/YsAcD29jaGwyFGoxGFYYiTJ0/S7u4uoiiiY8eO0Wg0wmQyodXVVRqNRhRFEfV6PZpMJhQEgReGIfm+T1EUeZ7nERF5URSR53leFEUeTcUTQngAPCGER0QeEVE8Fm+X/+aNMbMHwGNmb/o7Ecl/pdc0249mGiAeS17THF0kKRRSbiLJYNUpzZz3mQe0bF/LUuc7OjGauhDUcN/M+9lnWRdLzoAaKx6W3ievpXExfWyYiUgQkYhfy2Oz/QQzC2YWnuel/urGAMSvOR6XxgQzs+/7QgghpkqOhRCCfd8XURRxEAQchqHo9Xo8mUzY931eWVnh4XDIvV6PV1ZWsLOzw77v89GjR7G+vs5BEGBlZYVXV1fx+OOPAwDOnTvH9L3vfY/u3btH29vb+MIXvoCdnR06ceIEdnd3aXV1FcPhkPr9Pu3u7qLX6xEACoKAdnd3KQYuABJCeCsrKySEIGb2hBCeEMLzfZ+EEDEQc//GoJbe++p+6mvP82IFQLEiUF/P/slKIAV4ZibJK6CZ9aHYWygBEJW7hLzYZXsOgCQWtrqyYvUYM/DGL0FELAE9pRBmboKQlEgM+tTrqe0SQlIUmdczoEfK+9R23V/P80QURex5nvA8Lx7j0WjEM8XBsSI5evQoh2HIAHgymfDRo0cxHo95dXWVh8Mhjh49ynfu3MGxY8f46tWrePzxxxE888wzBAAnT57E+vo6jh8/js8++4x+93d/V7V+CXgki4/hcEhBEJAMthh8URRREAS5oI8t9+y1LwE3Zd2l1750/MTKy2PSOZCiBPL+6a6zEPBpV7zc0i966a79LLK3VeIZkPK7sOq5QW5mPf8rb9P9i7cJ6Tlh6bWYhQmZ5ypnbUKavqXMs5QOp+Z/wzAUvu+TRNqL+LzDMMTq6iqHYUi9Xg+TySRzX+LXm5ub9Nxzz/HGxgZeeeUVrK+vIzh16hR//vOfpytXruDUqVM4duwYHn/8cT569CgNh0OeTCY4efIkjUYjZmaaaRhaWVnhmfXk2WIgPDvZ2D3yZrEUz7RW7gXObojQrQ0n3xhJc8ca2ouPq4JUduclL4BnN1H+S5KFIMVikPIAsnTuqbEcsFNelsUgLDgs1t30XnCecpVAxir3IIcF8pj0Xk5exMASs20p6694BIn7H1v/2GrP9s28lz8Tu/rxNp31F0KI2UOeWHlm5iAIYu8kxheIiEejEQBwEAQgIl5ZWcH6+jr3ej1eXV3F7u4unzhxAjs7O3j48CFeeumlKQl49uxZBkBnz57FxYsX+Xd+53fQ7/dx79496vf7cVxBOzs7ot/vU6/XE0EQYDwew/d9TCYTbxaXUBAEYub+C8/zvCAIkhDA8zyS3ffYA5i5Rt6Ug/EyLr7k6ieeAwCKxyWvgmTPYfZ9CScw0wsZryDeJpGEufF/rLDU51hWDIoV0j7syn5aEJh4DlVDDMNjWnfRy64pdsfLziHeTzIenN2Fc3kAydVPjIlq9WdgleN/FlN2LgVeFaySosgoBzlEmO2bGp9y0ql9YsMpwjDkGZ44fj/DG/d6PRFFEfr9vgjDEJPJhMfjMR87doxHoxH/1m/9FsbjMT7/+c/zeDzmwWCAb3/72zh37hzOnj3LKQv3/e9/H9/73vcAgC5evIgjR46g3+9TEAQIgoD8WSrQ933a2tqi48ePY0b00WAwoPi153nkeR6Nx+PZW49WVlZoMpnEIKUZIZiAVhlLXPwZj+CpSkSjFEgBvrydZHJQ2pekbYmLJfMFsnIoCRV0fAFpwGJEFtYk77qMNdjivqxDcM4+XDDGyJYkJCCX4nrIJJ+0PQV8aVsKmHL8nwN2luL3hPCTPQPf94Vs1ZUx7vV6YjQa8cwJEP1+n4UQ8XsWQvCRI0eS1xsbG3jiiSc4iiIWQiCKIoRhyGEYIgb+888/DwAs4VxJXWkeonPnztHZs2cBAB9++CFOnTqVesDv3LmDEydO0MbGBh0/fhybm5vkeR7NmEba29sjyfqmXksWOLHKYRh6vV6PZt6EF0URAfBmPEPMLcRATsX9ujHP82iWbUgUjZoZmHkTyfnMshG5nEG87+yYecpBDicoh1AkxV0lNSWYTsOR1uKr401X4zX9vBr+qOOa47A0xsoxWUfcKV/AOpDHbnLsEivbU/9i4kzaN8P4S+z8bC0PkXH9deFAzN7HY7NwWfi+z2EYiiAIeDKZcBAEQvU2ZEUlKyVm5scee4wB8Pb2NoQQ/LnPfY43NjZw/PhxvnPnDp84cSJ1/yScJpY+lxw1dPdMGPDkoV5fX8fJkyfzrGTR66r/vJnSoCAIvLzt8WshRAx0L2cf7eelz2X+SdtS1yFxBCRnF2TXXwk3Sr0JheTSjVGOy2wUOuhc+bzPS+DLuOKasSKrnXLLJRdfjt3VNF4CfiFEAn71n7JNFBB9qVhf+pzI2YcBJKA2OH7ZP5S8BgCWcMWGadHSNCs1JKCopsIoeujrKg0TRQKJSfUaKh9UzCyUego5743DC9NaBEsuf103XX3AUQEIhda9ZJsJCIXytwpwK4HZ4H4ZA7povIzzoZYZaGqoPHK9DM14mVKpq2CKPl/lWFX+lo2ZgL0NPoArvOeKisHkbxmoqnzGFKBcQZGZWudKIC7b1iTNTEuSgiIL+5gAoK5yMR0ny8duw9JTDaDb8gxQAzAm42z52KbWly3cx2YueMMakwDLIU1uFFU4BjUESR3Gnlr4ni6zA9zR71jV+nEL39PmdS+lBNj/0sYP1dR9bjMdRwfsN+n62G4i8AFTAIf5IaNDAnonbT1A7DojOHFyaMVzt8CJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhx4hSAEydOnAJw4sSJUwBOnDhxCsCJEydOAThx4sQpACdOnDgF4MSJE6cAnDhxYlH+P+B5MeB+eNGIAAAAAElFTkSuQmCC);background-position:right top;background-repeat:no-repeat}#scheduledTaskStatus{width:520px;margin:40px auto 60px auto}#scheduledTaskStatus th.process{text-align:left;font-weight:bold;background-color:#f4f4f4;min-height:30px;vertical-align:middle}#scheduledTaskStatus td.description{font-size:.9em;min-height:60px}#scheduledTaskStatus td.progress{padding:8px 10px}#scheduledTaskStatus td.finishedRedirect{background-position:right center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAALAPQAAP///zNah+Hm7dng6O7x9DddiTNah1d3nJqtw3+Xs8fS3k5vlm6JqaGzx4KatcrU4FFymDZciHGMq+ru8t/l7Pb3+V9+oeLo7vT2+MTP3LLB0dTc5fHz9gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA);padding-right:20px}#scheduledTaskStatus td.exception{background-color:#ffd8d8}div.logEventsViewport{border:1px solid #bbb;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}div.logEventsViewport div.logEventsViewportContainer{overflow-y:auto;overflow-x:hidden}div.logEventsViewport div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}div.logEventsViewport table.logEventsViewport{padding:0;margin:0;background-color:#bbb;table-layout:fixed}div.logEventsViewport table.logEventsViewport>thead>tr{background-color:#eee}div.logEventsViewport table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}div.logEventsViewport table.logEventsViewport>thead>tr>th.icon{width:20px}div.logEventsViewport table.logEventsViewport>thead>tr>th.timestamp{width:155px}div.logEventsViewport table.logEventsViewport>thead>tr>th.eventType{width:180px}div.logEventsViewport table.logEventsViewport>tbody>tr{background-color:#fff}div.logEventsViewport table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}div.logEventsViewport table.logEventsViewport>tbody>tr>td{padding:2px}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}div.logEventsViewport table.logEventsViewport>tbody>tr>td.timestamp{width:155px}div.logEventsViewport table.logEventsViewport>tbody>tr>td.eventType{width:180px}#enrolStatus #sessions .session{width:280px;padding:4px 4px 4px 72px;margin:8px;border:5px solid #efefef;-moz-border-radius:0 20px 0 0;-webkit-border-radius:0 20px 0 0;border-radius:0 20px 0 0;background-color:#f5f5f5;background-repeat:no-repeat,no-repeat;background-position:36px 36px,4px 4px;-moz-background-size:32px,64px;-o-background-size:32px,64px;-webkit-background-size:32px,64px;background-size:32px,64px;min-height:72px;cursor:pointer}#enrolStatus #sessions .session>h3{padding-bottom:3px;border-bottom:1px dashed #ccc}#enrolStatus #sessions .session>h3 span.details{font-size:.8em}#enrolStatus #sessions .session>p.sessionStart{color:#888;font-size:.8em;margin-bottom:2px}#enrolStatus #sessions .session>p.sessionStatus{font-size:.9em;height:1.6em;overflow:hidden;margin-bottom:3px}#enrolStatus #sessions .session:hover{border:5px solid #6c7a87;background-color:#dfe1f8}#dialogSession .sessionHeader{width:400px;float:left;padding:0 0 0 134px;background-repeat:no-repeat,no-repeat;background-position:96px 96px,0 0;-moz-background-size:32px,128px;-o-background-size:32px,128px;-webkit-background-size:32px,128px;background-size:32px,128px;min-height:134px}#dialogSession .sessionHeader>h2{padding-bottom:0}#dialogSession .sessionHeader>table{margin-top:4px}#dialogSession .sessionHeader>table th{width:128px;text-align:right}#dialogSession .sessionHeader>table td,#dialogSession .sessionHeader>table th{padding:1px 2px}#dialogSession .sessionProgress{width:320px;float:right;text-align:right}#dialogSession .sessionProgress>p.sessionStart{color:#888;margin-bottom:2px}#dialogSession .sessionProgress>p.sessionStatus{height:1.6em;overflow:hidden;margin-bottom:3px}#dialogSession .sessionInfoContainer>div{float:left;width:428px;overflow:auto}#dialogSession .sessionInfoContainer .sessionInfoMessages{height:440px;border:1px solid #bbb;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages div.logEventsViewportContainer{overflow:auto}#dialogSession .sessionInfoContainer .sessionInfoMessages div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport{padding:0;margin:0;background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr{background-color:#eee}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.icon{width:20px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.timestamp{width:155px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.eventType{width:180px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr{background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td{padding:2px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.timestamp{width:155px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.eventType{width:180px}#dialogSession .sessionInfoContainer .sessionInfoConsole{margin-left:6px;background-color:#222;color:#0f0;font-family:Consolas,"Courier New",monospace;border:4px solid #ccc;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;padding:2px;height:430px}#Config_DocumentTemplates_JobSubTypes{border:1px dashed #d8d8d8;background-color:#fff;padding:4px;margin-top:6px}#Config_DocumentTemplates_JobSubTypes>h4{margin-bottom:4px}#Config_DocumentTemplates_JobSubTypes #Config_DocumentTemplates_JobSubTypes_Update{margin-top:4px}#Config_DocumentTemplates_JobSubTypes_Update_Dialog #Config_DocumentTemplates_JobSubTypes_Update_Dialog_Types{margin:0 0 8px 0}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .jobTypes{padding:6px 0}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .jobTypes .jobSubTypes{background-color:#f2f2f2;border-left:4px solid #d8d8d8;padding:4px 0 4px 8px;margin:4px 0 0 6px}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .checkboxBulkSelectContainer{font-size:.8em}#dialogBulkGenerate .brief{margin:0 0 8px 0}#dialogBulkGenerate .brief .scopeDescBulkGenerate{font-weight:bold}#dialogBulkGenerate .brief div.examples{margin:8px auto;width:300px}#dialogBulkGenerate .brief div.examples div{margin:2px 4px 2px 0;width:150px;float:left}#dialogBulkGenerate .brief div.examples div.example1{width:100px}#dialogBulkGenerate textarea{width:100%;height:200px;margin:0 auto}#importStatus #sessions .session{padding:4px;margin-bottom:10px;border:1px solid #efefef;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#f5f5f5;min-height:72px}#importStatus #sessions .session .sessionLeftPane{width:48%;float:left}#importStatus #sessions .session .sessionLeftPane>h3{padding-bottom:3px;border-bottom:1px dashed #ccc}#importStatus #sessions .session .sessionLeftPane>h3 span.details{font-size:.8em}#importStatus #sessions .session .sessionRightPane{width:48%;float:right;text-align:right}#importStatus #sessions .session .sessionRightPane>p.sessionStart{color:#888;font-size:.8em;margin-bottom:2px}#importStatus #sessions .session .sessionRightPane>p.sessionStatus{font-size:.9em;height:1.6em;overflow:hidden;margin-bottom:3px}#importStatus #sessions .session .sessionPages>.sessionPage{min-height:56px;min-width:256px;float:left;margin:3px 0 3px 0;padding:170px 0 0 0;background-color:#fff;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;border:1px solid #eee;background-repeat:no-repeat;background-position:center top}#importStatus #sessions .session .sessionPages>.sessionPage>.sessionPageDetails{height:84px;padding:2px 4px 0 4px;background-color:rgba(255,255,255,.8)}#importStatus #sessions .session .sessionPages>.sessionPage>.sessionPageDetails p.sessionStatus{font-size:.9em;height:1.6em;margin-bottom:3px}#importStatus #sessions .session .sessionInfoMessages{margin-top:6px;border:1px solid #bbb;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#fff}#importStatus #sessions .session .sessionInfoMessages div.logEventsViewportContainer{max-height:220px;overflow:auto}#importStatus #sessions .session .sessionInfoMessages div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport{padding:0;margin:0;background-color:#fff}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr{background-color:#eee}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.icon{width:20px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.timestamp{width:155px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.eventType{width:180px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr{background-color:#fff}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td{padding:2px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.timestamp{width:155px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.eventType{width:180px}#undetectedPagesContainer #undetectedPages{list-style:none;margin:0;padding:0}#undetectedPagesContainer #undetectedPages>.undetectedPage{float:left;margin:4px;border:1px solid #f4f4f4;background-color:#fcfcfc;height:256px;width:256px;background-position:top center;background-repeat:no-repeat;cursor:pointer}#undetectedPagesContainer #undetectedPages>.undetectedPage>.pageDetails{margin-top:232px;height:24px;text-align:center}#undetectedPagesContainer #undetectedPages>.undetectedPage:hover{border:1px solid #d8d8d8;background-color:#f4f4f4}#undetectedPageDialog>.pagePreview{height:700px;background-position:top center;background-repeat:no-repeat}#undetectedPageDialog .actions{border-top:1px solid #d1d1d1;padding-top:8px;margin-top:8px;text-align:right}.deviceBatches #DeviceBatch_PurchaseDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_PurchaseDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_WarrantyDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_WarrantyDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_InsuranceDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_InsuranceDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_Comments{width:570px;height:200px}#plugins .pageMenuArea a>h3{display:inline;color:#335a87}#plugins .pageMenuArea a>h3:hover{color:#5e8cc2}#plugins .pageMenuArea .pageMenuBlurb{padding-left:18px}#plugins .pageMenuArea .pageMenuBlurb i{font-size:.9em}#plugins #pageMenu td .pageMenuArea:not(:last-child){padding-bottom:5px;margin-bottom:10px}#plugins #pageMenu td .pageMenuArea>a,#plugins #pageMenu td .pageMenuArea>h3{color:#333}#plugins #pageMenu td .pageMenuArea>a:hover,#plugins #pageMenu td .pageMenuArea>h3:hover{color:#335a87}#pluginCatalog #pluginCatalogHeading{margin-bottom:20px;text-align:right}#pluginCatalog .pluginItem .pluginItemBlurb{margin:4px 0 4px 2px;padding:0 4px;border-left:4px solid #f4f4f4}#pluginCatalog .pluginItem .pluginItemBlurb *{padding:0;margin:0}#pluginCatalog .pluginItem .pageMenuBlurb i{font-size:.9em}#pluginCatalog .pluginItem>h2:first-child{min-height:22px}#pluginCatalog .pluginItem>h2:first-child i{font-size:.9em;padding-right:4px;color:#333}#pluginCatalog .pluginItem>h2:first-child a{float:right;font-size:12px}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node{padding:1px;border:none}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node>span.fancytree-icon{background:none;display:inline-block;font-family:FontAwesome;font-size:1.2em;width:14px}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-ef>span.fancytree-icon:before{color:#9e9e9e;font-size:1em;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-cf>span.fancytree-icon:before{color:#9e9e9e;font-size:1em;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-c>span.fancytree-icon:before{color:#e51400;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-c.fancytree-selected>span.fancytree-icon:before{color:#60a917;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node.fancytree-selected{font-style:normal;background:none}#Config_AuthRoles_Subjects li,#Config_AuthRoles_Subjects_Update_Dialog_List li{padding:4px 0 4px 4px}#Config_AuthRoles_Subjects li i.fa-user,#Config_AuthRoles_Subjects_Update_Dialog_List li i.fa-user,#Config_AuthRoles_Subjects li i.fa-users,#Config_AuthRoles_Subjects_Update_Dialog_List li i.fa-users{min-width:22px}#Config_AuthRoles_Subjects_Update_Dialog{display:none}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li{cursor:pointer}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li:hover{background-color:#f4f4f4}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li:hover .remove{opacity:.8}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li .remove:hover{opacity:1}#Config_Location{margin-top:10px}#Config_Location #Config_Location_Unrestricted,#Config_Location #Config_Location_List,#Config_Location #Config_Location_Optional,#Config_Location #Config_Location_Restricted{display:none;margin-top:6px}#Config_Location_List_Dialog{display:none}#Config_Location_List_Dialog #Config_Location_List_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_Location_List_Dialog #Config_Location_List_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_Location_List_Dialog #Config_Location_List_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li{padding:2px 0 2px 4px;cursor:pointer}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li:hover{background-color:#f4f4f4}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li:hover .remove{opacity:.8}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li .remove:hover{opacity:1}#Config_Location_ListImport_Dialog{display:none}#Config_Location_ListImport_Dialog #Config_Location_ListImport_Dialog_Overwrite_Container{margin:6px 0}#Config_Location_ListImport_Dialog #Config_Location_ListImport_Dialog_LocationList{width:100%;height:200px;margin:0 auto}#Config_JobQueues_Index i{width:1.2857142857142858em;text-align:center}#Config_JobQueues_Icon{display:block;margin:0 0 10px 10px}#Config_JobQueues_Icon_Update_Dialog{display:none}#Config_JobQueues_Icon_Update_Dialog div.colours{text-align:center;font-size:30px}#Config_JobQueues_Icon_Update_Dialog div.colours i{cursor:pointer;padding:1px;opacity:.9}#Config_JobQueues_Icon_Update_Dialog div.colours i:hover{opacity:1}#Config_JobQueues_Icon_Update_Dialog div.colours i.selected{opacity:1}#Config_JobQueues_Icon_Update_Dialog div.icons{text-align:center;font-size:34px;background-color:#fff;border:1px solid #d1d1d1;margin:6px 0 14px 0}#Config_JobQueues_Icon_Update_Dialog div.icons i{width:1.2857142857142858em;text-align:center;cursor:pointer;padding:6px 0;color:#333;opacity:.6}#Config_JobQueues_Icon_Update_Dialog div.icons i:hover{opacity:.9;color:inherit}#Config_JobQueues_Icon_Update_Dialog div.icons i.selected{opacity:1;color:inherit}#Config_JobQueues_JobSubTypes_Update{margin:8px 0}#Config_JobQueues_JobSubTypes_Update_Dialog #Config_JobQueues_JobSubTypes_Update_Dialog_Types{margin:0 0 8px 0}#Config_JobQueues_JobSubTypes_Update_Dialog .jobTypes{padding:6px 0}#Config_JobQueues_JobSubTypes_Update_Dialog .jobTypes .jobSubTypes{background-color:#f2f2f2;border-left:4px solid #d8d8d8;padding:4px 0 4px 8px;margin:4px 0 0 6px}#Config_JobQueues_JobSubTypes_Update_Dialog .checkboxBulkSelectContainer{font-size:.8em}#Config_JobQueues_Subjects li,#Config_JobQueues_Subjects_Update_Dialog_List li{padding:4px 0 4px 4px}#Config_JobQueues_Subjects li i.fa-user,#Config_JobQueues_Subjects_Update_Dialog_List li i.fa-user,#Config_JobQueues_Subjects li i.fa-users,#Config_JobQueues_Subjects_Update_Dialog_List li i.fa-users{width:1.2857142857142858em;text-align:center}#Config_JobQueues_Subjects_Update_Dialog{display:none}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li{cursor:pointer}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li:hover{background-color:#f4f4f4}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li:hover .remove{opacity:.8}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li .remove:hover{opacity:1} \ No newline at end of file +.tableData{border:solid 1px #f4f4f4;border-collapse:collapse}.tableData>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}.tableData>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}.tableData>thead>tr>th,.tableData>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}.tableData>tbody>tr:hover>td{background-color:#fefefe}.tableData>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}.tableData>tfoot>tr>th,.tableData>tfoot>tr>td{background-color:#f4f4f4}.tableDataDark{border:solid 1px #d8d8d8;border-collapse:collapse}.tableDataDark td{border:solid 1px #d8d8d8;background-color:#fff}.tableDataDark th{background-color:#eee;border:solid 1px #d8d8d8}.tableDataContainer{background-color:#fff}.tableDataVertical{border:solid 1px #f4f4f4;border-collapse:collapse}.tableDataVertical>tbody>tr:nth-child(odd){background-color:#f4f4f4;margin:0;padding:0}.tableDataVertical>tbody>tr>th.name{width:170px;text-align:right}.tableDataVertical table.sub>tbody>tr:not(:first-child)>th,.tableDataVertical table.sub>tbody>tr:not(:first-child)>td{border-top:1px dashed #aaa}.tableDataVertical table.sub>tbody>tr>th{font-weight:normal;text-align:right}.tableDataVertical table.sub>tbody>tr>th.name{text-align:right}.icon16{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer}.subtleUntilHover{-moz-opacity:.3;opacity:.3}.subtleUntilHover:hover{-moz-opacity:1;opacity:1}#updateAvailableContainer{float:right;border:1px dashed #ddd;background-color:#fff;font-size:.6em;line-height:1em;padding:10px 10px 4px 70px;text-align:right;height:50px}#updateAvailableContainer i{position:absolute;display:block;height:64px;width:64px;vertical-align:middle;margin-left:-70px;font-size:50px;color:#e51400}#updateAvailableContainer a.button{font-size:12px;margin-top:8px}#expressionEditor #expressionEditorExceptionContainer{display:none;border:1px dashed #ff9696;background-color:#ffd8d8;margin:10px 0;padding:10px}#expressionEditor #expressionEditorContainer{border:1px solid #1e6dab;background-color:#f4f4f4;height:100px}.expressionTree span.dynatree-node span.dynatree-icon{background-image:url(data:image/png;base64,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);background-position-y:0}.expressionTree span.dynatree-node.object span.dynatree-icon{background-position-x:0}.expressionTree span.dynatree-node.parameter span.dynatree-icon{background-position-x:-16px}.expressionTree span.dynatree-node.function span.dynatree-icon{background-position-x:-32px}.expressionTree span.dynatree-node.property span.dynatree-icon{background-position-x:-48px}table.expressionsTable{border:solid 1px #f4f4f4;border-collapse:collapse}table.expressionsTable>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}table.expressionsTable>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}table.expressionsTable>thead>tr>th,table.expressionsTable>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}table.expressionsTable>tbody>tr:hover>td{background-color:#fefefe}table.expressionsTable>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}table.expressionsTable>tfoot>tr>th,table.expressionsTable>tfoot>tr>td{background-color:#f4f4f4}table.expressionsTable td.parseError{background-color:#ffd8d8}#AttachmentType_FilterExpression{width:375px}#deviceComponents{border:solid 1px #f4f4f4;border-collapse:collapse}#deviceComponents>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff}#deviceComponents>tbody>tr:nth-child(odd)>td{background-color:#fcfcfc}#deviceComponents>thead>tr>th,#deviceComponents>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4}#deviceComponents>tbody>tr:hover>td{background-color:#fefefe}#deviceComponents>tbody>tr:hover:nth-child(odd)>td{background-color:#fafafa}#deviceComponents>tfoot>tr>th,#deviceComponents>tfoot>tr>td{background-color:#f4f4f4}#deviceComponents tr th.actions{width:20px}#deviceComponents tr input.description{width:300px}#deviceComponents tr input.cost{width:75px}#deviceComponents tr i.remove{font-size:1.6em;color:#e51400;cursor:pointer;opacity:.8}#deviceComponents tr i.remove:hover{opacity:1}#deviceComponents tr i.fa-list-alt{color:#1e6dab;font-size:1.6em;cursor:pointer}#deviceComponents tr i.fa-asterisk{color:#fa6800;font-size:1em;left:10px;top:3px;cursor:pointer}#deviceComponents tr input.updating{background-position:right center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAALAPQAAP///zNah+Hm7dng6O7x9DddiTNah1d3nJqtw3+Xs8fS3k5vlm6JqaGzx4KatcrU4FFymDZciHGMq+ru8t/l7Pb3+V9+oeLo7vT2+MTP3LLB0dTc5fHz9gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA)}#organisationAddresses{font-size:.9em}#organisationAddresses tr:not(:last-child){border-bottom:1px dashed #aaa}#organisationAddresses th{padding:2px;font-weight:bold;width:200px}#organisationAddresses td{padding:2px;vertical-align:middle}#organisationAddresses tr:nth-child(even){background-color:#fff}#organisationAddresses i.fa{font-size:1.7em;cursor:pointer}#organisationAddresses i.fa.delete{color:#e51400;opacity:.8}#organisationAddresses i.fa.delete:hover{opacity:1}#organisationAddresses i.fa.edit{color:#1e6dab}ul#loggingEntries{overflow:auto;max-height:230px;padding-left:20px}table.deviceProfileTable th.name{width:300px}table.deviceProfileTable th.type{width:120px}table.deviceProfileTable th.deviceCount{width:120px}#configurationDeviceProfileShow #ComputerNameTemplate{width:300px}#configurationDeviceProfileShow #expressionBrowserAnchor{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACKUlEQVQ4jaWTTU4UURDHf/W6gXFgJlHZKFvEe3gBvYhewXgGTXRpOILhGESGgEuNjB9N/BgCTJjufvXhonsQ176kkqpFVf2q6v8kIvifV77b2wsAU6MsCop/LCEpISIkEUAoioSZYWZczOeUp6en1ZPHT+4FQXgQERDBMrZlHACOpIKcM23bMN3fr0pEcDfub21x9/YdIhwR6QoJWFY8wF2JAHfH3fh8MoUISoGugxnPnj1lZ2eHg/cHTL9MMTdy09K0LVkVy8rsbMZkMukpoRQRRBIAZ2czNjbWWV1bZXY2I6WCpq5pmgY1ZXoypaoqAEQSsSQQ6Tb67es3Xr9+Q103PHy4w+Fkgpoxn1/y8eMn6rq+3v4yp0TkOvpeVaytreHuHB4egggXFxdUVUVZrrKxXmJuLBYLut15PwIwGo1IqTuTSGJlJfj1+xdXV1eMx2PCnTZn3B1VRZY6kJ5gc3MTEenO1Cy4nF9SpILxaIya4maUqrgqdU8QEd0IArgbOStFmVFVNCuqirtjalgYboa5A3KDIAJEGA7XiQiauiZnZTgcXhdwM7RXX1ZlsbgCEUTkL8GD7W3UjMGtAUUqMDMiosf3niqTVbk1GLDUT5nV5Oj4A293d1G1647m3qvOb/hGBLRty9HxB8xM5OWrV49+/vj5wuk07x4CEZ2clxcWUuqclFIgiSIJo9Houdz8zufn56siMgBKoACkNwdcRDIRzWg8bpY5fwBYR4lbku/2TAAAAABJRU5ErkJggg==);text-decoration:none}#configurationDeviceProfileShow #displayComputerNameTemplate{margin:0 0 6px 0}#configurationDeviceProfileShow #displayOrganisationalUnit{margin:0 0 6px 0}.organisationalUnitTree span.fancytree-node{padding:1px;border:none}.organisationalUnitTree span.fancytree-node>span.fancytree-icon{background:none;display:inline-block;font-family:FontAwesome;font-size:1.2em;width:14px}.organisationalUnitTree span.fancytree-ico-ef>span.fancytree-icon:before{color:#1e6dab;font-size:1em;content:""}.organisationalUnitTree span.fancytree-ico-cf>span.fancytree-icon:before{color:#1e6dab;font-size:1em;content:""}.organisationalUnitTree ul.fancytree-container>li>span>span.fancytree-icon:before{color:#fa6800;font-size:1em;content:""}.organisationalUnitTree span.fancytree-node.fancytree-selected{font-style:normal;background:none}#configurationDocumentTemplateExpressionBrowser{padding-right:275px;background-image:url(data:image/png;base64,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);background-position:right top;background-repeat:no-repeat}#scheduledTaskStatus{width:520px;margin:40px auto 60px auto}#scheduledTaskStatus th.process{text-align:left;font-weight:bold;background-color:#f4f4f4;min-height:30px;vertical-align:middle}#scheduledTaskStatus td.description{font-size:.9em;min-height:60px}#scheduledTaskStatus td.progress{padding:8px 10px}#scheduledTaskStatus td.finishedRedirect{background-position:right center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAALAPQAAP///zNah+Hm7dng6O7x9DddiTNah1d3nJqtw3+Xs8fS3k5vlm6JqaGzx4KatcrU4FFymDZciHGMq+ru8t/l7Pb3+V9+oeLo7vT2+MTP3LLB0dTc5fHz9gAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCwAAACwAAAAAEAALAAAFLSAgjmRpnqSgCuLKAq5AEIM4zDVw03ve27ifDgfkEYe04kDIDC5zrtYKRa2WQgAh+QQJCwAAACwAAAAAEAALAAAFJGBhGAVgnqhpHIeRvsDawqns0qeN5+y967tYLyicBYE7EYkYAgAh+QQJCwAAACwAAAAAEAALAAAFNiAgjothLOOIJAkiGgxjpGKiKMkbz7SN6zIawJcDwIK9W/HISxGBzdHTuBNOmcJVCyoUlk7CEAAh+QQJCwAAACwAAAAAEAALAAAFNSAgjqQIRRFUAo3jNGIkSdHqPI8Tz3V55zuaDacDyIQ+YrBH+hWPzJFzOQQaeavWi7oqnVIhACH5BAkLAAAALAAAAAAQAAsAAAUyICCOZGme1rJY5kRRk7hI0mJSVUXJtF3iOl7tltsBZsNfUegjAY3I5sgFY55KqdX1GgIAIfkECQsAAAAsAAAAABAACwAABTcgII5kaZ4kcV2EqLJipmnZhWGXaOOitm2aXQ4g7P2Ct2ER4AMul00kj5g0Al8tADY2y6C+4FIIACH5BAkLAAAALAAAAAAQAAsAAAUvICCOZGme5ERRk6iy7qpyHCVStA3gNa/7txxwlwv2isSacYUc+l4tADQGQ1mvpBAAIfkECQsAAAAsAAAAABAACwAABS8gII5kaZ7kRFGTqLLuqnIcJVK0DeA1r/u3HHCXC/aKxJpxhRz6Xi0ANAZDWa+kEAA7AAAAAAAAAAAA);padding-right:20px}#scheduledTaskStatus td.exception{background-color:#ffd8d8}div.logEventsViewport{border:1px solid #bbb;-moz-border-radius:4px 4px 0 0;-webkit-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}div.logEventsViewport div.logEventsViewportContainer{overflow-y:auto;overflow-x:hidden}div.logEventsViewport div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}div.logEventsViewport table.logEventsViewport{padding:0;margin:0;background-color:#bbb;table-layout:fixed}div.logEventsViewport table.logEventsViewport>thead>tr{background-color:#eee}div.logEventsViewport table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}div.logEventsViewport table.logEventsViewport>thead>tr>th.icon{width:20px}div.logEventsViewport table.logEventsViewport>thead>tr>th.timestamp{width:155px}div.logEventsViewport table.logEventsViewport>thead>tr>th.eventType{width:180px}div.logEventsViewport table.logEventsViewport>tbody>tr{background-color:#fff}div.logEventsViewport table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}div.logEventsViewport table.logEventsViewport>tbody>tr>td{padding:2px}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}div.logEventsViewport table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}div.logEventsViewport table.logEventsViewport>tbody>tr>td.timestamp{width:155px}div.logEventsViewport table.logEventsViewport>tbody>tr>td.eventType{width:180px}#enrolStatus #sessions .session{width:280px;padding:4px 4px 4px 72px;margin:8px;border:5px solid #efefef;-moz-border-radius:0 20px 0 0;-webkit-border-radius:0 20px 0 0;border-radius:0 20px 0 0;background-color:#f5f5f5;background-repeat:no-repeat,no-repeat;background-position:36px 36px,4px 4px;-moz-background-size:32px,64px;-o-background-size:32px,64px;-webkit-background-size:32px,64px;background-size:32px,64px;min-height:72px;cursor:pointer}#enrolStatus #sessions .session>h3{padding-bottom:3px;border-bottom:1px dashed #ccc}#enrolStatus #sessions .session>h3 span.details{font-size:.8em}#enrolStatus #sessions .session>p.sessionStart{color:#888;font-size:.8em;margin-bottom:2px}#enrolStatus #sessions .session>p.sessionStatus{font-size:.9em;height:1.6em;overflow:hidden;margin-bottom:3px}#enrolStatus #sessions .session:hover{border:5px solid #6c7a87;background-color:#dfe1f8}#dialogSession .sessionHeader{width:400px;float:left;padding:0 0 0 134px;background-repeat:no-repeat,no-repeat;background-position:96px 96px,0 0;-moz-background-size:32px,128px;-o-background-size:32px,128px;-webkit-background-size:32px,128px;background-size:32px,128px;min-height:134px}#dialogSession .sessionHeader>h2{padding-bottom:0}#dialogSession .sessionHeader>table{margin-top:4px}#dialogSession .sessionHeader>table th{width:128px;text-align:right}#dialogSession .sessionHeader>table td,#dialogSession .sessionHeader>table th{padding:1px 2px}#dialogSession .sessionProgress{width:320px;float:right;text-align:right}#dialogSession .sessionProgress>p.sessionStart{color:#888;margin-bottom:2px}#dialogSession .sessionProgress>p.sessionStatus{height:1.6em;overflow:hidden;margin-bottom:3px}#dialogSession .sessionInfoContainer>div{float:left;width:428px;overflow:auto}#dialogSession .sessionInfoContainer .sessionInfoMessages{height:440px;border:1px solid #bbb;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages div.logEventsViewportContainer{overflow:auto}#dialogSession .sessionInfoContainer .sessionInfoMessages div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport{padding:0;margin:0;background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr{background-color:#eee}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.icon{width:20px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.timestamp{width:155px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>thead>tr>th.eventType{width:180px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr{background-color:#fff}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td{padding:2px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.timestamp{width:155px}#dialogSession .sessionInfoContainer .sessionInfoMessages table.logEventsViewport>tbody>tr>td.eventType{width:180px}#dialogSession .sessionInfoContainer .sessionInfoConsole{margin-left:6px;background-color:#222;color:#0f0;font-family:Consolas,"Courier New",monospace;border:4px solid #ccc;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;padding:2px;height:430px}#Config_DocumentTemplates_JobSubTypes{border:1px dashed #d8d8d8;background-color:#fff;padding:4px;margin-top:6px}#Config_DocumentTemplates_JobSubTypes>h4{margin-bottom:4px}#Config_DocumentTemplates_JobSubTypes #Config_DocumentTemplates_JobSubTypes_Update{margin-top:4px}#Config_DocumentTemplates_JobSubTypes_Update_Dialog #Config_DocumentTemplates_JobSubTypes_Update_Dialog_Types{margin:0 0 8px 0}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .jobTypes{padding:6px 0}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .jobTypes .jobSubTypes{background-color:#f2f2f2;border-left:4px solid #d8d8d8;padding:4px 0 4px 8px;margin:4px 0 0 6px}#Config_DocumentTemplates_JobSubTypes_Update_Dialog .checkboxBulkSelectContainer{font-size:.8em}#dialogBulkGenerate .brief{margin:0 0 8px 0}#dialogBulkGenerate .brief .scopeDescBulkGenerate{font-weight:bold}#dialogBulkGenerate .brief div.examples{margin:8px auto;width:300px}#dialogBulkGenerate .brief div.examples div{margin:2px 4px 2px 0;width:150px;float:left}#dialogBulkGenerate .brief div.examples div.example1{width:100px}#dialogBulkGenerate textarea{width:100%;height:200px;margin:0 auto}#importStatus #sessions .session{padding:4px;margin-bottom:10px;border:1px solid #efefef;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#f5f5f5;min-height:72px}#importStatus #sessions .session .sessionLeftPane{width:48%;float:left}#importStatus #sessions .session .sessionLeftPane>h3{padding-bottom:3px;border-bottom:1px dashed #ccc}#importStatus #sessions .session .sessionLeftPane>h3 span.details{font-size:.8em}#importStatus #sessions .session .sessionRightPane{width:48%;float:right;text-align:right}#importStatus #sessions .session .sessionRightPane>p.sessionStart{color:#888;font-size:.8em;margin-bottom:2px}#importStatus #sessions .session .sessionRightPane>p.sessionStatus{font-size:.9em;height:1.6em;overflow:hidden;margin-bottom:3px}#importStatus #sessions .session .sessionPages>.sessionPage{min-height:56px;min-width:256px;float:left;margin:3px 0 3px 0;padding:170px 0 0 0;background-color:#fff;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;border:1px solid #eee;background-repeat:no-repeat;background-position:center top}#importStatus #sessions .session .sessionPages>.sessionPage>.sessionPageDetails{height:84px;padding:2px 4px 0 4px;background-color:rgba(255,255,255,.8)}#importStatus #sessions .session .sessionPages>.sessionPage>.sessionPageDetails p.sessionStatus{font-size:.9em;height:1.6em;margin-bottom:3px}#importStatus #sessions .session .sessionInfoMessages{margin-top:6px;border:1px solid #bbb;-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#fff}#importStatus #sessions .session .sessionInfoMessages div.logEventsViewportContainer{max-height:220px;overflow:auto}#importStatus #sessions .session .sessionInfoMessages div.logEventsViewportContainer .logEventsViewportNoLogs{padding-top:20px;text-align:center;font-style:italic}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport{padding:0;margin:0;background-color:#fff}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr{background-color:#eee}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th{padding:4px 2px;font-weight:bold;border-bottom:1px solid #bbb}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.icon{width:20px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.timestamp{width:155px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>thead>tr>th.eventType{width:180px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr{background-color:#fff}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr:nth-child(even){background-color:#eee}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td{padding:2px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon{width:20px;vertical-align:middle;text-align:center}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i{display:block;font-size:1.2em}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-info-circle{color:#1e6dab}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-triangle{color:#f0a30a}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.icon>i.fa-exclamation-circle{color:#e51400}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.timestamp{width:155px}#importStatus #sessions .session .sessionInfoMessages table.logEventsViewport>tbody>tr>td.eventType{width:180px}#undetectedPagesContainer #undetectedPages{list-style:none;margin:0;padding:0}#undetectedPagesContainer #undetectedPages>.undetectedPage{float:left;margin:4px;border:1px solid #f4f4f4;background-color:#fcfcfc;height:256px;width:256px;background-position:top center;background-repeat:no-repeat;cursor:pointer}#undetectedPagesContainer #undetectedPages>.undetectedPage>.pageDetails{margin-top:232px;height:24px;text-align:center}#undetectedPagesContainer #undetectedPages>.undetectedPage:hover{border:1px solid #d8d8d8;background-color:#f4f4f4}#undetectedPageDialog>.pagePreview{height:700px;background-position:top center;background-repeat:no-repeat}#undetectedPageDialog .actions{border-top:1px solid #d1d1d1;padding-top:8px;margin-top:8px;text-align:right}.deviceBatches #DeviceBatch_PurchaseDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_PurchaseDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_WarrantyDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_WarrantyDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_InsuranceDetails_Container{padding:5px 0 5px 5px}.deviceBatches #DeviceBatch_InsuranceDetails{width:570px;height:200px}.deviceBatches #DeviceBatch_Comments{width:570px;height:200px}#plugins .pageMenuArea a>h3{display:inline;color:#335a87}#plugins .pageMenuArea a>h3:hover{color:#5e8cc2}#plugins .pageMenuArea .pageMenuBlurb{padding-left:18px}#plugins .pageMenuArea .pageMenuBlurb i{font-size:.9em}#plugins #pageMenu td .pageMenuArea:not(:last-child){padding-bottom:5px;margin-bottom:10px}#plugins #pageMenu td .pageMenuArea>a,#plugins #pageMenu td .pageMenuArea>h3{color:#333}#plugins #pageMenu td .pageMenuArea>a:hover,#plugins #pageMenu td .pageMenuArea>h3:hover{color:#335a87}#pluginCatalog #pluginCatalogHeading{margin-bottom:20px;text-align:right}#pluginCatalog .pluginItem .pluginItemBlurb{margin:4px 0 4px 2px;padding:0 4px;border-left:4px solid #f4f4f4}#pluginCatalog .pluginItem .pluginItemBlurb *{padding:0;margin:0}#pluginCatalog .pluginItem .pageMenuBlurb i{font-size:.9em}#pluginCatalog .pluginItem>h2:first-child{min-height:22px}#pluginCatalog .pluginItem>h2:first-child i{font-size:.9em;padding-right:4px;color:#333}#pluginCatalog .pluginItem>h2:first-child a{float:right;font-size:12px}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node{padding:1px;border:none}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node>span.fancytree-icon{background:none;display:inline-block;font-family:FontAwesome;font-size:1.2em;width:14px}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-ef>span.fancytree-icon:before{color:#9e9e9e;font-size:1em;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-cf>span.fancytree-icon:before{color:#9e9e9e;font-size:1em;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-c>span.fancytree-icon:before{color:#e51400;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-ico-c.fancytree-selected>span.fancytree-icon:before{color:#60a917;content:""}#Config_AuthRoles_Show #Config_AuthRoles_Claims_Tree span.fancytree-node.fancytree-selected{font-style:normal;background:none}#Config_AuthRoles_Subjects li,#Config_AuthRoles_Subjects_Update_Dialog_List li{padding:4px 0 4px 4px}#Config_AuthRoles_Subjects li i.fa-user,#Config_AuthRoles_Subjects_Update_Dialog_List li i.fa-user,#Config_AuthRoles_Subjects li i.fa-users,#Config_AuthRoles_Subjects_Update_Dialog_List li i.fa-users{min-width:22px}#Config_AuthRoles_Subjects_Update_Dialog{display:none}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li{cursor:pointer}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li:hover{background-color:#f4f4f4}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li:hover .remove{opacity:.8}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_AuthRoles_Subjects_Update_Dialog #Config_AuthRoles_Subjects_Update_Dialog_List li .remove:hover{opacity:1}#Config_Location{margin-top:10px}#Config_Location #Config_Location_Unrestricted,#Config_Location #Config_Location_List,#Config_Location #Config_Location_Optional,#Config_Location #Config_Location_Restricted{display:none;margin-top:6px}#Config_Location_List_Dialog{display:none}#Config_Location_List_Dialog #Config_Location_List_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_Location_List_Dialog #Config_Location_List_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_Location_List_Dialog #Config_Location_List_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li{padding:2px 0 2px 4px;cursor:pointer}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li:hover{background-color:#f4f4f4}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li:hover .remove{opacity:.8}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_Location_List_Dialog #Config_Location_List_Dialog_List li .remove:hover{opacity:1}#Config_Location_ListImport_Dialog{display:none}#Config_Location_ListImport_Dialog #Config_Location_ListImport_Dialog_Overwrite_Container{margin:6px 0}#Config_Location_ListImport_Dialog #Config_Location_ListImport_Dialog_LocationList{width:100%;height:200px;margin:0 auto}#Config_JobQueues_Index i{width:1.2857142857142858em;text-align:center}#Config_JobQueues_Icon{display:block;margin:0 0 10px 10px}#Config_JobQueues_Icon_Update_Dialog{display:none}#Config_JobQueues_Icon_Update_Dialog div.colours{text-align:center;font-size:30px}#Config_JobQueues_Icon_Update_Dialog div.colours i{cursor:pointer;padding:1px;opacity:.9}#Config_JobQueues_Icon_Update_Dialog div.colours i:hover{opacity:1}#Config_JobQueues_Icon_Update_Dialog div.colours i.selected{opacity:1}#Config_JobQueues_Icon_Update_Dialog div.icons{text-align:center;font-size:34px;background-color:#fff;border:1px solid #d1d1d1;margin:6px 0 14px 0}#Config_JobQueues_Icon_Update_Dialog div.icons i{width:1.2857142857142858em;text-align:center;cursor:pointer;padding:6px 0;color:#333;opacity:.6}#Config_JobQueues_Icon_Update_Dialog div.icons i:hover{opacity:.9;color:inherit}#Config_JobQueues_Icon_Update_Dialog div.icons i.selected{opacity:1;color:inherit}#Config_JobQueues_JobSubTypes_Update{margin:8px 0}#Config_JobQueues_JobSubTypes_Update_Dialog #Config_JobQueues_JobSubTypes_Update_Dialog_Types{margin:0 0 8px 0}#Config_JobQueues_JobSubTypes_Update_Dialog .jobTypes{padding:6px 0}#Config_JobQueues_JobSubTypes_Update_Dialog .jobTypes .jobSubTypes{background-color:#f2f2f2;border-left:4px solid #d8d8d8;padding:4px 0 4px 8px;margin:4px 0 0 6px}#Config_JobQueues_JobSubTypes_Update_Dialog .checkboxBulkSelectContainer{font-size:.8em}#Config_JobQueues_Subjects li,#Config_JobQueues_Subjects_Update_Dialog_List li{padding:4px 0 4px 4px}#Config_JobQueues_Subjects li i.fa-user,#Config_JobQueues_Subjects_Update_Dialog_List li i.fa-user,#Config_JobQueues_Subjects li i.fa-users,#Config_JobQueues_Subjects_Update_Dialog_List li i.fa-users{width:1.2857142857142858em;text-align:center}#Config_JobQueues_Subjects_Update_Dialog{display:none}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_ListContainer{height:280px;overflow-y:auto;background-color:#fff;border:1px solid #d8d8d8}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_None{padding-top:15px;display:block;text-align:center}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_AddContainer{padding-top:10px;padding-left:10px}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li{cursor:pointer}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li:hover{background-color:#f4f4f4}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li:hover .remove{opacity:.8}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li .remove{margin-top:2px;padding-right:6px;float:right;cursor:pointer;opacity:0;color:#e51400;font-size:1.3em}#Config_JobQueues_Subjects_Update_Dialog #Config_JobQueues_Subjects_Update_Dialog_List li .remove:hover{opacity:1} \ No newline at end of file diff --git a/Disco.Web/Controllers/SearchController.cs b/Disco.Web/Controllers/SearchController.cs index 9e194f15..471d8d01 100644 --- a/Disco.Web/Controllers/SearchController.cs +++ b/Disco.Web/Controllers/SearchController.cs @@ -203,7 +203,7 @@ namespace Disco.Web.Controllers } case "userid": Authorization.Require(Claims.User.Search); - var user = Database.Users.FirstOrDefault(u => u.Id == term); + var user = Database.Users.FirstOrDefault(u => u.UserId == term); if (user != null) return RedirectToAction(MVC.User.Show(term)); else diff --git a/Disco.Web/Controllers/UserController.cs b/Disco.Web/Controllers/UserController.cs index 23fe5d7e..0c1b0cc0 100644 --- a/Disco.Web/Controllers/UserController.cs +++ b/Disco.Web/Controllers/UserController.cs @@ -4,6 +4,7 @@ using Disco.Models.UI.User; using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Authorization.Roles; +using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Plugins.Features.UIExtension; using Disco.Services.Users; using Disco.Services.Web; @@ -29,8 +30,16 @@ namespace Disco.Web.Controllers #region Show [DiscoAuthorize(Claims.User.Show)] - public virtual ActionResult Show(string id) + public virtual ActionResult Show(string id, string Domain) { + if (string.IsNullOrWhiteSpace(id)) + throw new ArgumentNullException("id", "The User Id must be provided"); + + if (string.IsNullOrEmpty(Domain)) + id = ActiveDirectory.PrimaryDomain.NetBiosName + @"\" + id; + else + id = Domain + @"\" + id; + var m = new Models.User.ShowModel(); Database.Configuration.LazyLoadingEnabled = true; @@ -48,7 +57,7 @@ namespace Disco.Web.Controllers m.User = Database.Users .Include("DeviceUserAssignments.Device.DeviceModel").Include("UserAttachments") - .FirstOrDefault(um => um.Id == id); + .FirstOrDefault(um => um.UserId == id); if (m.User == null) throw new ArgumentException("Unknown User Id", "id"); diff --git a/Disco.Web/Disco.Web.csproj b/Disco.Web/Disco.Web.csproj index 1ca80da8..5b595785 100644 --- a/Disco.Web/Disco.Web.csproj +++ b/Disco.Web/Disco.Web.csproj @@ -196,6 +196,7 @@ + @@ -543,6 +544,7 @@ True True + True True diff --git a/Disco.Web/Extensions/T4MVCExtensions.cs b/Disco.Web/Extensions/T4MVCExtensions.cs new file mode 100644 index 00000000..3c006f85 --- /dev/null +++ b/Disco.Web/Extensions/T4MVCExtensions.cs @@ -0,0 +1,78 @@ +using Disco.Services; +using Disco.Services.Interop.ActiveDirectory; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace Disco.Web.Controllers +{ + public partial class UserController + { + internal static void T4MVCAddUserIdRouteValues(T4MVC_System_Web_Mvc_ActionResult callInfo, string UserId) + { + var splitId = UserExtensions.SplitUserId(UserId); + + if (splitId.Item1 == null) + throw new ArgumentException("The User Id is not in the correct format ({Domain}\\{Id})", "id"); + + string userDomain; + if (splitId.Item1.Equals(ActiveDirectory.PrimaryDomain.NetBiosName, StringComparison.InvariantCultureIgnoreCase)) + userDomain = null; // Url doesn't contain Domain if it is the default. + else + userDomain = splitId.Item1; + + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", splitId.Item2); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Domain", userDomain); + } + + [NonAction] + public virtual System.Web.Mvc.ActionResult Show(string id) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Show); + + T4MVCAddUserIdRouteValues(callInfo, id); + + return callInfo; + } + } +} + +namespace Disco.Web.Areas.API.Controllers +{ + public partial class UserController + { + [NonAction] + public virtual ActionResult AttachmentUpload(string id, string Comments) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AttachmentUpload); + + Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Comments", Comments); + + return callInfo; + } + + [NonAction] + public virtual ActionResult Attachments(string id) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Attachments); + + Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); + + return callInfo; + } + + [NonAction] + public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.GeneratePdf); + + Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DocumentTemplateId", DocumentTemplateId); + + return callInfo; + } + } +} \ No newline at end of file diff --git a/Disco.Web/T4MVC.cs b/Disco.Web/T4MVC.cs index fad717d8..a0908761 100644 --- a/Disco.Web/T4MVC.cs +++ b/Disco.Web/T4MVC.cs @@ -2122,6 +2122,7 @@ namespace Disco.Web.Controllers public class ActionParamsClass_Show { public readonly string id = "id"; + public readonly string Domain = "Domain"; } static readonly ViewsClass s_views = new ViewsClass(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] @@ -2180,13 +2181,14 @@ namespace Disco.Web.Controllers return callInfo; } - partial void ShowOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id); + partial void ShowOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string Domain); - public override System.Web.Mvc.ActionResult Show(string id) + public override System.Web.Mvc.ActionResult Show(string id, string Domain) { var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Show); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id); - ShowOverride(callInfo, id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Domain", Domain); + ShowOverride(callInfo, id, Domain); return callInfo; } @@ -4626,7 +4628,6 @@ namespace Disco.Web.Areas.API.Controllers public readonly string UpdateProvisionADAccount = "UpdateProvisionADAccount"; public readonly string UpdateAssignedUserLocalAdmin = "UpdateAssignedUserLocalAdmin"; public readonly string UpdateAllowUntrustedReimageJobEnrolment = "UpdateAllowUntrustedReimageJobEnrolment"; - public readonly string OrganisationalUnits = "OrganisationalUnits"; public readonly string Delete = "Delete"; public readonly string Default = "Default"; public readonly string DefaultAddDeviceOffline = "DefaultAddDeviceOffline"; @@ -4650,7 +4651,6 @@ namespace Disco.Web.Areas.API.Controllers public const string UpdateProvisionADAccount = "UpdateProvisionADAccount"; public const string UpdateAssignedUserLocalAdmin = "UpdateAssignedUserLocalAdmin"; public const string UpdateAllowUntrustedReimageJobEnrolment = "UpdateAllowUntrustedReimageJobEnrolment"; - public const string OrganisationalUnits = "OrganisationalUnits"; public const string Delete = "Delete"; public const string Default = "Default"; public const string DefaultAddDeviceOffline = "DefaultAddDeviceOffline"; @@ -5022,15 +5022,6 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } - partial void OrganisationalUnitsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo); - - public override System.Web.Mvc.ActionResult OrganisationalUnits() - { - var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.OrganisationalUnits); - OrganisationalUnitsOverride(callInfo); - return callInfo; - } - partial void DeleteOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, bool? redirect); public override System.Web.Mvc.ActionResult Delete(int id, bool? redirect) @@ -9180,6 +9171,24 @@ namespace Disco.Web.Areas.API.Controllers { return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateMultiSiteMode); } + [NonAction] + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchScope() + { + return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchScope); + } + [NonAction] + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public virtual System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest() + { + return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest); + } + [NonAction] + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public virtual System.Web.Mvc.ActionResult UpdateProxySettings() + { + return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateProxySettings); + } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public SystemController Actions { get { return MVC.API.System; } } @@ -9204,6 +9213,10 @@ namespace Disco.Web.Areas.API.Controllers public readonly string UpdateOrganisationAddress = "UpdateOrganisationAddress"; public readonly string DeleteOrganisationAddress = "DeleteOrganisationAddress"; public readonly string UpdateMultiSiteMode = "UpdateMultiSiteMode"; + public readonly string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope"; + public readonly string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest"; + public readonly string DomainOrganisationalUnits = "DomainOrganisationalUnits"; + public readonly string UpdateProxySettings = "UpdateProxySettings"; } [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] @@ -9217,6 +9230,10 @@ namespace Disco.Web.Areas.API.Controllers public const string UpdateOrganisationAddress = "UpdateOrganisationAddress"; public const string DeleteOrganisationAddress = "DeleteOrganisationAddress"; public const string UpdateMultiSiteMode = "UpdateMultiSiteMode"; + public const string UpdateActiveDirectorySearchScope = "UpdateActiveDirectorySearchScope"; + public const string UpdateActiveDirectorySearchEntireForest = "UpdateActiveDirectorySearchEntireForest"; + public const string DomainOrganisationalUnits = "DomainOrganisationalUnits"; + public const string UpdateProxySettings = "UpdateProxySettings"; } @@ -9269,6 +9286,36 @@ namespace Disco.Web.Areas.API.Controllers public readonly string MultiSiteMode = "MultiSiteMode"; public readonly string redirect = "redirect"; } + static readonly ActionParamsClass_UpdateActiveDirectorySearchScope s_params_UpdateActiveDirectorySearchScope = new ActionParamsClass_UpdateActiveDirectorySearchScope(); + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public ActionParamsClass_UpdateActiveDirectorySearchScope UpdateActiveDirectorySearchScopeParams { get { return s_params_UpdateActiveDirectorySearchScope; } } + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public class ActionParamsClass_UpdateActiveDirectorySearchScope + { + public readonly string Containers = "Containers"; + public readonly string redirect = "redirect"; + } + static readonly ActionParamsClass_UpdateActiveDirectorySearchEntireForest s_params_UpdateActiveDirectorySearchEntireForest = new ActionParamsClass_UpdateActiveDirectorySearchEntireForest(); + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public ActionParamsClass_UpdateActiveDirectorySearchEntireForest UpdateActiveDirectorySearchEntireForestParams { get { return s_params_UpdateActiveDirectorySearchEntireForest; } } + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public class ActionParamsClass_UpdateActiveDirectorySearchEntireForest + { + public readonly string SearchEntireForest = "SearchEntireForest"; + public readonly string redirect = "redirect"; + } + static readonly ActionParamsClass_UpdateProxySettings s_params_UpdateProxySettings = new ActionParamsClass_UpdateProxySettings(); + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public ActionParamsClass_UpdateProxySettings UpdateProxySettingsParams { get { return s_params_UpdateProxySettings; } } + [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] + public class ActionParamsClass_UpdateProxySettings + { + public readonly string ProxyAddress = "ProxyAddress"; + public readonly string ProxyPort = "ProxyPort"; + public readonly string ProxyUsername = "ProxyUsername"; + public readonly string ProxyPassword = "ProxyPassword"; + public readonly string redirect = "redirect"; + } static readonly ViewsClass s_views = new ViewsClass(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public ViewsClass Views { get { return s_views; } } @@ -9383,6 +9430,51 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } + partial void UpdateActiveDirectorySearchScopeOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, System.Collections.Generic.List Containers, bool redirect); + + public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchScope(System.Collections.Generic.List Containers, bool redirect) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchScope); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Containers", Containers); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect); + UpdateActiveDirectorySearchScopeOverride(callInfo, Containers, redirect); + return callInfo; + } + + partial void UpdateActiveDirectorySearchEntireForestOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, bool SearchEntireForest, bool redirect); + + public override System.Web.Mvc.ActionResult UpdateActiveDirectorySearchEntireForest(bool SearchEntireForest, bool redirect) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateActiveDirectorySearchEntireForest); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "SearchEntireForest", SearchEntireForest); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect); + UpdateActiveDirectorySearchEntireForestOverride(callInfo, SearchEntireForest, redirect); + return callInfo; + } + + partial void DomainOrganisationalUnitsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo); + + public override System.Web.Mvc.ActionResult DomainOrganisationalUnits() + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.DomainOrganisationalUnits); + DomainOrganisationalUnitsOverride(callInfo); + return callInfo; + } + + partial void UpdateProxySettingsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect); + + public override System.Web.Mvc.ActionResult UpdateProxySettings(string ProxyAddress, int? ProxyPort, string ProxyUsername, string ProxyPassword, bool redirect) + { + var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.UpdateProxySettings); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ProxyAddress", ProxyAddress); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ProxyPort", ProxyPort); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ProxyUsername", ProxyUsername); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "ProxyPassword", ProxyPassword); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "redirect", redirect); + UpdateProxySettingsOverride(callInfo, ProxyAddress, ProxyPort, ProxyUsername, ProxyPassword, redirect); + return callInfo; + } + } } @@ -9529,6 +9621,7 @@ namespace Disco.Web.Areas.API.Controllers public class ActionParamsClass_AttachmentUpload { public readonly string id = "id"; + public readonly string Domain = "Domain"; public readonly string Comments = "Comments"; } static readonly ActionParamsClass_Attachment s_params_Attachment = new ActionParamsClass_Attachment(); @@ -9546,6 +9639,7 @@ namespace Disco.Web.Areas.API.Controllers public class ActionParamsClass_Attachments { public readonly string id = "id"; + public readonly string Domain = "Domain"; } static readonly ActionParamsClass_AttachmentRemove s_params_AttachmentRemove = new ActionParamsClass_AttachmentRemove(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] @@ -9562,6 +9656,7 @@ namespace Disco.Web.Areas.API.Controllers public class ActionParamsClass_GeneratePdf { public readonly string id = "id"; + public readonly string Domain = "Domain"; public readonly string DocumentTemplateId = "DocumentTemplateId"; } static readonly ViewsClass s_views = new ViewsClass(); @@ -9613,14 +9708,15 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } - partial void AttachmentUploadOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string Comments); + partial void AttachmentUploadOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string Domain, string Comments); - public override System.Web.Mvc.ActionResult AttachmentUpload(string id, string Comments) + public override System.Web.Mvc.ActionResult AttachmentUpload(string id, string Domain, string Comments) { var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AttachmentUpload); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Domain", Domain); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Comments", Comments); - AttachmentUploadOverride(callInfo, id, Comments); + AttachmentUploadOverride(callInfo, id, Domain, Comments); return callInfo; } @@ -9634,13 +9730,14 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } - partial void AttachmentsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id); + partial void AttachmentsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string Domain); - public override System.Web.Mvc.ActionResult Attachments(string id) + public override System.Web.Mvc.ActionResult Attachments(string id, string Domain) { var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Attachments); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id); - AttachmentsOverride(callInfo, id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Domain", Domain); + AttachmentsOverride(callInfo, id, Domain); return callInfo; } @@ -9654,14 +9751,15 @@ namespace Disco.Web.Areas.API.Controllers return callInfo; } - partial void GeneratePdfOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string DocumentTemplateId); + partial void GeneratePdfOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string Domain, string DocumentTemplateId); - public override System.Web.Mvc.ActionResult GeneratePdf(string id, string DocumentTemplateId) + public override System.Web.Mvc.ActionResult GeneratePdf(string id, string Domain, string DocumentTemplateId) { var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.GeneratePdf); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id); + ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Domain", Domain); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DocumentTemplateId", DocumentTemplateId); - GeneratePdfOverride(callInfo, id, DocumentTemplateId); + GeneratePdfOverride(callInfo, id, Domain, DocumentTemplateId); return callInfo; } @@ -11266,14 +11364,6 @@ namespace Disco.Web.Areas.Config.Controllers } - static readonly ActionParamsClass_Index s_params_Index = new ActionParamsClass_Index(); - [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] - public ActionParamsClass_Index IndexParams { get { return s_params_Index; } } - [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] - public class ActionParamsClass_Index - { - public readonly string config = "config"; - } static readonly ViewsClass s_views = new ViewsClass(); [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] public ViewsClass Views { get { return s_views; } } @@ -11304,16 +11394,6 @@ namespace Disco.Web.Areas.Config.Controllers return callInfo; } - partial void IndexOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, Disco.Web.Areas.Config.Models.SystemConfig.IndexModel config); - - public override System.Web.Mvc.ActionResult Index(Disco.Web.Areas.Config.Models.SystemConfig.IndexModel config) - { - var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Index); - ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "config", config); - IndexOverride(callInfo, config); - return callInfo; - } - } } diff --git a/Disco.Web/Views/Device/AddOffline.generated.cs b/Disco.Web/Views/Device/AddOffline.generated.cs index 1e5c6bf1..a1146b1c 100644 --- a/Disco.Web/Views/Device/AddOffline.generated.cs +++ b/Disco.Web/Views/Device/AddOffline.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/DeviceParts/_AssignmentHistory.generated.cs b/Disco.Web/Views/Device/DeviceParts/_AssignmentHistory.generated.cs index 41a33305..14989958 100644 --- a/Disco.Web/Views/Device/DeviceParts/_AssignmentHistory.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_AssignmentHistory.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device.DeviceParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/DeviceParts/_Certificates.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Certificates.generated.cs index bdcf2896..1d5a0439 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Certificates.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Certificates.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device.DeviceParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs index bb95d2d6..45c2f03d 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Details.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Device/DeviceParts/_Jobs.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Jobs.generated.cs index 53c6e293..50a28bc9 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Jobs.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Jobs.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Device/DeviceParts/_Resources.cshtml b/Disco.Web/Views/Device/DeviceParts/_Resources.cshtml index d2b1dd27..9ca311e9 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Resources.cshtml +++ b/Disco.Web/Views/Device/DeviceParts/_Resources.cshtml @@ -31,7 +31,7 @@ { @da.DocumentTemplate.Description} else { @da.Comments }} - @da.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId == CurrentUser.Id)) + @da.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId == CurrentUser.UserId)) {}@da.Timestamp.ToFullDateTime() } @@ -125,7 +125,7 @@ } else if (canRemoveOwnAttachments) { - buildAttachment(a, (a.AuthorId === '@(CurrentUser.Id)'), quick); + buildAttachment(a, (a.AuthorId === '@(CurrentUser.UserId)'), quick); } else { diff --git a/Disco.Web/Views/Device/DeviceParts/_Resources.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Resources.generated.cs index 62717dc1..6ec7a2af 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Resources.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Resources.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -246,7 +246,7 @@ WriteLiteral(""); #line 34 "..\..\Views\Device\DeviceParts\_Resources.cshtml" - if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId == CurrentUser.Id)) + if (canRemoveAnyAttachments || (canRemoveOwnAttachments && da.TechUserId == CurrentUser.UserId)) { #line default @@ -267,14 +267,14 @@ WriteLiteral("(da.Timestamp.ToFullDateTime() + , Tuple.Create(Tuple.Create("", 2156), Tuple.Create(da.Timestamp.ToFullDateTime() #line default #line hidden -, 2152), false) +, 2156), false) ); WriteLiteral(" data-livestamp=\""); @@ -506,7 +506,7 @@ WriteLiteral("buildAttachment(a, (a.AuthorId === \'"); #line 128 "..\..\Views\Device\DeviceParts\_Resources.cshtml" - Write(CurrentUser.Id); + Write(CurrentUser.UserId); #line default diff --git a/Disco.Web/Views/Device/DeviceParts/_Subject.cshtml b/Disco.Web/Views/Device/DeviceParts/_Subject.cshtml index c12210f6..b59b1900 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Subject.cshtml +++ b/Disco.Web/Views/Device/DeviceParts/_Subject.cshtml @@ -13,7 +13,7 @@ Name: - @if (string.IsNullOrWhiteSpace(Model.Device.ComputerName)) + @if (string.IsNullOrWhiteSpace(Model.Device.DeviceDomainId)) { <Unknown/Not Allocated> } @@ -23,6 +23,19 @@ } + + Domain: + + @if (string.IsNullOrWhiteSpace(Model.Device.DeviceDomainId)) + { + <Unknown/Not Allocated> + } + else + { +

    @Model.Device.ComputerDomainName

    + } + + Asset: @@ -178,14 +191,14 @@
    @if (Authorization.Has(Claims.User.Show)) { - @Html.ActionLink(assignedUser.DisplayName, MVC.User.Show(assignedUser.Id)) + @Html.ActionLink(assignedUser.DisplayName, MVC.User.Show(assignedUser.UserId)) } else { @assignedUser.DisplayName }
    -
    @assignedUser.Id
    +
    @assignedUser.FriendlyId()
    @if (Authorization.Has(Claims.User.ShowDetails)) { if (!string.IsNullOrWhiteSpace(assignedUser.PhoneNumber)) diff --git a/Disco.Web/Views/Device/DeviceParts/_Subject.generated.cs b/Disco.Web/Views/Device/DeviceParts/_Subject.generated.cs index bded39b5..7595e59d 100644 --- a/Disco.Web/Views/Device/DeviceParts/_Subject.generated.cs +++ b/Disco.Web/Views/Device/DeviceParts/_Subject.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -79,7 +79,7 @@ WriteLiteral(">Name:\r\n \r\n #line 16 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - if (string.IsNullOrWhiteSpace(Model.Device.ComputerName)) + if (string.IsNullOrWhiteSpace(Model.Device.DeviceDomainId)) { @@ -126,6 +126,65 @@ WriteLiteral("\r\n"); } + #line default + #line hidden +WriteLiteral(" \r\n \r\n " + +" \r\n Domain:\r\n \r\n <" + +"td>"); + + + #line 29 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + if (string.IsNullOrWhiteSpace(Model.Device.DeviceDomainId)) + { + + + #line default + #line hidden +WriteLiteral(" <Unknown/Not Allocated>\r\n"); + + + #line 32 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + } + else + { + + + #line default + #line hidden +WriteLiteral(" "); + + + #line 35 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + Write(Model.Device.ComputerDomainName); + + + #line default + #line hidden +WriteLiteral("\r\n"); + + + #line 36 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + } + + #line default #line hidden WriteLiteral(" \r\n \r\n " + @@ -133,13 +192,13 @@ WriteLiteral(" \r\n " \r\n"); - #line 29 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 42 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 29 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 42 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.Device.Properties.AssetNumber)) { @@ -147,40 +206,40 @@ WriteLiteral(" \r\n #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.TextBoxFor(m => m.Device.AssetNumber, new { @class = "small discreet" })); #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(AjaxHelpers.AjaxSave()); #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(AjaxHelpers.AjaxLoader()); #line default #line hidden - #line 31 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else @@ -196,7 +255,7 @@ WriteLiteral(" class=\"small discreet\""); WriteLiteral(">"); - #line 35 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 48 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.AssetNumber ?? "Unknown"); @@ -205,7 +264,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 36 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 49 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -216,13 +275,13 @@ WriteLiteral(" \r\n " \r\n"); - #line 42 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 55 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 42 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 55 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.Device.Properties.Location)) { @@ -230,40 +289,40 @@ WriteLiteral(" \r\n #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.TextBoxFor(m => m.Device.Location, new { @class = "small discreet" })); #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(AjaxHelpers.AjaxSave()); #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(AjaxHelpers.AjaxLoader()); #line default #line hidden - #line 44 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 57 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else @@ -279,7 +338,7 @@ WriteLiteral(" class=\"small discreet\""); WriteLiteral(">"); - #line 48 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 61 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.Location ?? "Unknown"); @@ -288,7 +347,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 49 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 62 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -298,13 +357,13 @@ WriteLiteral(" \r\n " \r\n"); - #line 53 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 66 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 53 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 66 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.HasAny(Claims.Device.Properties.AssetNumber, Claims.Device.Properties.Location)) { @@ -314,13 +373,13 @@ WriteLiteral(" \r\n WriteLiteral(" \r\n"); - #line 63 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 76 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -399,7 +458,7 @@ WriteLiteral(" id=\"Device_Show_Details_Dates_Created\""); WriteLiteral(">"); - #line 70 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 83 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(CommonHelpers.FriendlyDate(Model.Device.CreatedDate)); @@ -408,13 +467,13 @@ WriteLiteral(">"); WriteLiteral("\r\n \r\n"); - #line 72 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 85 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 72 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 85 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.DecommissionedDate.HasValue) { @@ -430,7 +489,7 @@ WriteLiteral(" id=\"Device_Show_Details_Dates_Decommissioned\""); WriteLiteral(">"); - #line 77 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 90 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(CommonHelpers.FriendlyDate(Model.Device.DecommissionedDate)); @@ -439,7 +498,7 @@ WriteLiteral(">"); WriteLiteral("\r\n \r\n"); - #line 79 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 92 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -449,13 +508,13 @@ WriteLiteral("\r\n \r\n \r\n \r\n"); - #line 85 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 98 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 85 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 98 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.EnrolledDate.HasValue) { @@ -473,7 +532,7 @@ WriteLiteral(" id=\"Device_Show_Details_Asset_Enrolled_First\""); WriteLiteral(">"); - #line 87 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 100 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(CommonHelpers.FriendlyDate(Model.Device.EnrolledDate)); @@ -482,7 +541,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 88 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 101 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.LastEnrolDate.HasValue && Model.Device.EnrolledDate.Value != Model.Device.LastEnrolDate.Value) { @@ -500,7 +559,7 @@ WriteLiteral(" id=\"Device_Show_Details_Asset_Enrolled_Last\""); WriteLiteral(">"); - #line 90 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 103 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(CommonHelpers.FriendlyDate(Model.Device.LastEnrolDate)); @@ -509,7 +568,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 91 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 104 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } } else @@ -527,7 +586,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">Never\r\n"); - #line 96 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 109 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -536,7 +595,7 @@ WriteLiteral(">Never\r\n"); WriteLiteral(" "); - #line 97 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 110 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.AllowUnauthenticatedEnrol) { @@ -552,7 +611,7 @@ WriteLiteral(" title=\"Trusted Unauthenticated Enrolment is Allowed\""); WriteLiteral(">\r\n"); - #line 100 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 113 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -577,7 +636,7 @@ WriteLiteral(">Last Seen:\r\n \r\n " "); - #line 111 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 124 "..\..\Views\Device\DeviceParts\_Subject.cshtml" string lastSeenClass = null; if (Model.Device.LastNetworkLogonDate.HasValue) @@ -602,20 +661,20 @@ WriteLiteral("\r\n (lastSeenClass + #line 141 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 8060), Tuple.Create(lastSeenClass #line default #line hidden -, 7278), false) +, 8060), false) ); WriteLiteral(">"); - #line 128 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 141 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(CommonHelpers.FriendlyDate(Model.Device.LastNetworkLogonDate)); @@ -624,13 +683,13 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 129 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 142 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 129 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 142 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (!string.IsNullOrEmpty(Model.Device.ComputerName)) { @@ -650,7 +709,7 @@ WriteLiteral(@"> $.getJSON('"); - #line 137 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 150 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Url.Action(MVC.API.Device.LastNetworkLogonDate(Model.Device.SerialNumber))); @@ -682,7 +741,7 @@ WriteLiteral("\', function (response, result) {\r\n " \r\n"); - #line 162 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 175 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -696,13 +755,13 @@ WriteLiteral(" class=\"status\""); WriteLiteral(">\r\n"); - #line 167 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 180 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 167 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 180 "..\..\Views\Device\DeviceParts\_Subject.cshtml" var assignedUser = Model.Device.AssignedUser; @@ -717,13 +776,13 @@ WriteLiteral(">\r\n \r\n < " \r\n \r\n"); - #line 175 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 188 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 175 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 188 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (assignedUser != null) { @@ -743,13 +802,13 @@ WriteLiteral(" title=\"Display Name\""); WriteLiteral(">\r\n"); - #line 179 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 192 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 179 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 192 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.User.Show)) { @@ -757,15 +816,15 @@ WriteLiteral(">\r\n"); #line default #line hidden - #line 181 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - Write(Html.ActionLink(assignedUser.DisplayName, MVC.User.Show(assignedUser.Id))); + #line 194 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + Write(Html.ActionLink(assignedUser.DisplayName, MVC.User.Show(assignedUser.UserId))); #line default #line hidden - #line 181 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - + #line 194 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + } else { @@ -774,14 +833,14 @@ WriteLiteral(">\r\n"); #line default #line hidden - #line 185 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 198 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(assignedUser.DisplayName); #line default #line hidden - #line 185 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 198 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -798,8 +857,8 @@ WriteLiteral(" title=\"Id\""); WriteLiteral(">"); - #line 188 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - Write(assignedUser.Id); + #line 201 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + Write(assignedUser.FriendlyId()); #line default @@ -807,13 +866,13 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 189 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 202 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 189 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 202 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.User.ShowDetails)) { if (!string.IsNullOrWhiteSpace(assignedUser.PhoneNumber)) @@ -831,7 +890,7 @@ WriteLiteral(" title=\"Phone Number\""); WriteLiteral(">"); - #line 193 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 206 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(assignedUser.PhoneNumber); @@ -840,7 +899,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 194 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 207 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } if (!string.IsNullOrWhiteSpace(assignedUser.EmailAddress)) { @@ -856,21 +915,21 @@ WriteLiteral(" title=\"Email Address\""); WriteLiteral(">(Model.Device.AssignedUser.EmailAddress + #line 210 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 12759), Tuple.Create(Model.Device.AssignedUser.EmailAddress #line default #line hidden -, 11963), false) +, 12759), false) ); WriteLiteral(">"); - #line 197 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 210 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(assignedUser.EmailAddress); @@ -879,7 +938,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 198 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 211 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } } @@ -889,7 +948,7 @@ WriteLiteral("\r\n"); WriteLiteral(" \r\n"); - #line 201 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 214 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else { @@ -904,7 +963,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">Not Assigned\r\n"); - #line 205 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 218 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -914,13 +973,13 @@ WriteLiteral(" \r\n " \r\n \r\n"); - #line 210 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 223 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 210 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 223 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.Device.Actions.GenerateDocuments)) { @@ -938,7 +997,7 @@ WriteLiteral(">\r\n"); WriteLiteral(" "); - #line 213 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 226 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.DropDownList("Device_Show_GenerateDocument", Model.DocumentTemplatesSelectListItems)); @@ -952,7 +1011,7 @@ WriteLiteral(">\r\n $(function () {\r\n "ar generatePdfUrl = \'"); - #line 216 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 229 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Url.Action(MVC.API.Device.GeneratePdf(Model.Device.SerialNumber.ToString(), null))); @@ -973,7 +1032,7 @@ WriteLiteral(@"?DocumentTemplateId='; "); - #line 228 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 241 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -996,7 +1055,7 @@ WriteLiteral(" title=\"Device Profile\""); WriteLiteral(">"); - #line 234 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 247 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.Config.DeviceProfile.Show)) { @@ -1004,14 +1063,14 @@ WriteLiteral(">"); #line default #line hidden - #line 236 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 249 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLink(Model.Device.DeviceProfile.Name, MVC.Config.DeviceProfile.Index(Model.Device.DeviceProfileId))); #line default #line hidden - #line 236 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 249 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else @@ -1021,14 +1080,14 @@ WriteLiteral(">"); #line default #line hidden - #line 240 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 253 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.DeviceProfile.Name); #line default #line hidden - #line 240 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 253 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1046,7 +1105,7 @@ WriteLiteral(">Distribution:\r\n \r\n " "); - #line 246 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 259 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.DeviceProfile.DistributionType.ToString()); @@ -1061,7 +1120,7 @@ WriteLiteral(">Address:\r\n \r\n ""); - #line 252 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 265 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.DeviceProfileDefaultOrganisationAddress != null) { @@ -1076,7 +1135,7 @@ WriteLiteral(" id=\"Device_Show_Policies_Profile_Address\""); WriteLiteral(">"); - #line 255 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 268 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.DeviceProfileDefaultOrganisationAddress.Name); @@ -1085,7 +1144,7 @@ WriteLiteral(">"); WriteLiteral("\r\n"); - #line 256 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 269 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else { @@ -1102,7 +1161,7 @@ WriteLiteral(" class=\"smallMessage\""); WriteLiteral(">None\r\n"); - #line 260 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 273 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1117,7 +1176,7 @@ WriteLiteral(">Provision Account:\r\n \r\ " "); - #line 267 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 280 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.DeviceProfile.ProvisionADAccount ? "Active Directory" : "No"); @@ -1132,7 +1191,7 @@ WriteLiteral(">Allocate Certificate:\r\n " "); - #line 273 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 286 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.DeviceProfileCertificateProvider != null ? Model.DeviceProfileCertificateProvider.Name : "No"); @@ -1142,13 +1201,13 @@ WriteLiteral("\r\n \r\n < " \r\n"); - #line 277 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 290 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 277 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 290 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanUpdateDeviceProfile()) { @@ -1156,14 +1215,14 @@ WriteLiteral("\r\n \r\n < #line default #line hidden - #line 279 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 292 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Update Profile", MVC.API.Device.UpdateDeviceProfileId(Model.Device.SerialNumber, null, true), "Device_Show_Policies_Profile_Actions_Update_Button")); #line default #line hidden - #line 279 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 292 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -1185,13 +1244,13 @@ WriteLiteral(" class=\"none\""); WriteLiteral(">\r\n"); - #line 284 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 297 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 284 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 297 "..\..\Views\Device\DeviceParts\_Subject.cshtml" foreach (var dp in Model.DeviceProfiles.OrderBy(i => i.Name)) { @@ -1206,7 +1265,7 @@ WriteLiteral(" type=\"radio\""); WriteLiteral(" data-deviceprofileid=\""); - #line 287 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 300 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(dp.Id); @@ -1216,45 +1275,45 @@ WriteLiteral("\""); WriteLiteral(" name=\"DeviceProfile\""); -WriteAttribute("id", Tuple.Create(" id=\"", 17177), Tuple.Create("\"", 17204) -, Tuple.Create(Tuple.Create("", 17182), Tuple.Create("DeviceProfile_", 17182), true) +WriteAttribute("id", Tuple.Create(" id=\"", 17973), Tuple.Create("\"", 18000) +, Tuple.Create(Tuple.Create("", 17978), Tuple.Create("DeviceProfile_", 17978), true) - #line 287 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 17196), Tuple.Create(dp.Id + #line 300 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 17992), Tuple.Create(dp.Id #line default #line hidden -, 17196), false) +, 17992), false) ); WriteLiteral(" />(dp.Id + #line 300 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 18030), Tuple.Create(dp.Id #line default #line hidden -, 17234), false) +, 18030), false) ); -WriteAttribute("title", Tuple.Create(" title=\"", 17243), Tuple.Create("\"", 17287) -, Tuple.Create(Tuple.Create("", 17251), Tuple.Create("Distribution:", 17251), true) +WriteAttribute("title", Tuple.Create(" title=\"", 18039), Tuple.Create("\"", 18083) +, Tuple.Create(Tuple.Create("", 18047), Tuple.Create("Distribution:", 18047), true) - #line 287 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create(" ", 17264), Tuple.Create(dp.DistributionType + #line 300 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create(" ", 18060), Tuple.Create(dp.DistributionType #line default #line hidden -, 17265), false) +, 18061), false) ); WriteLiteral(">"); - #line 287 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 300 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(dp.Name); @@ -1263,7 +1322,7 @@ WriteLiteral(">"); WriteLiteral(" \r\n"); - #line 288 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 301 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1276,7 +1335,7 @@ WriteLiteral(" \r\n"); - #line 461 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 474 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1735,7 +1794,7 @@ WriteLiteral(" title=\"Model Description\""); WriteLiteral(">"); - #line 468 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 481 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Authorization.Has(Claims.Config.DeviceModel.Show)) { @@ -1743,14 +1802,14 @@ WriteLiteral(">"); #line default #line hidden - #line 470 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 483 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLink(Model.Device.DeviceModel.ToString(), MVC.Config.DeviceModel.Index(Model.Device.DeviceModelId))); #line default #line hidden - #line 470 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 483 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } else @@ -1760,14 +1819,14 @@ WriteLiteral(">"); #line default #line hidden - #line 474 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 487 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.DeviceModel.ToString()); #line default #line hidden - #line 474 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 487 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1779,14 +1838,14 @@ WriteLiteral(" id=\"Device_Show_Aspects_Model_Image\""); WriteLiteral(" alt=\"Model Image\""); -WriteAttribute("src", Tuple.Create(" src=\"", 29908), Tuple.Create("\"", 30018) +WriteAttribute("src", Tuple.Create(" src=\"", 30704), Tuple.Create("\"", 30814) - #line 476 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 29914), Tuple.Create(Url.Action(MVC.API.DeviceModel.Image(Model.Device.DeviceModelId, Model.Device.DeviceModel.ImageHash())) + #line 489 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 30710), Tuple.Create(Url.Action(MVC.API.DeviceModel.Image(Model.Device.DeviceModelId, Model.Device.DeviceModel.ImageHash())) #line default #line hidden -, 29914), false) +, 30710), false) ); WriteLiteral(" />\r\n \r\n \r\n \r\n \r\n \r\n"); - #line 483 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 496 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 483 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 496 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanCreateJob()) { Html.BundleDeferred("~/ClientScripts/Modules/Disco-CreateJob"); @@ -1816,14 +1875,14 @@ WriteLiteral(">\r\n"); #line default #line hidden - #line 486 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 499 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Create Job", MVC.Job.Create(Model.Device.SerialNumber, Model.Device.AssignedUserId), "buttonCreateJob")); #line default #line hidden - #line 486 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 499 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1833,7 +1892,7 @@ WriteLiteral(">\r\n"); WriteLiteral(" "); - #line 488 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 501 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanUpdateAssignment()) { @@ -1841,14 +1900,14 @@ WriteLiteral(" "); #line default #line hidden - #line 490 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 503 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Update Assignment", MVC.API.Device.UpdateAssignedUserId(Model.Device.SerialNumber, null, true), "Device_Show_User_Actions_Assign_Button")); #line default #line hidden - #line 490 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 503 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -1889,13 +1948,13 @@ WriteLiteral(@"> "); - #line 503 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 516 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 503 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 516 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (assignedUser != null) { @@ -1917,7 +1976,7 @@ WriteLiteral(@" WriteLiteral("\r\n"); - #line 514 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 527 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1948,7 +2007,7 @@ WriteLiteral("\r\n \"Assign\": function () {\r\n " source: \'"); - #line 545 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 558 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Url.Action(MVC.API.User.UpstreamUsers())); @@ -1978,7 +2037,7 @@ WriteLiteral(@"', "); - #line 566 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 579 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -1987,7 +2046,7 @@ WriteLiteral(@"', WriteLiteral(" "); - #line 567 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 580 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanUpdateTrustEnrol()) { @@ -1995,14 +2054,14 @@ WriteLiteral(" "); #line default #line hidden - #line 569 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 582 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Trust Enrol", MVC.API.Device.UpdateAllowUnauthenticatedEnrol(Model.Device.SerialNumber, true.ToString(), true), "Device_Show_Device_Actions_TrustEnrol_Button")); #line default #line hidden - #line 569 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 582 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -2036,7 +2095,7 @@ WriteLiteral("> \r\n This action will al "claiming to have the Serial Number \'"); - #line 575 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 588 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.SerialNumber); @@ -2096,7 +2155,7 @@ WriteLiteral(@"> "); - #line 614 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 627 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -2105,7 +2164,7 @@ WriteLiteral(@"> WriteLiteral(" "); - #line 615 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 628 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanUpdateUntrustEnrol()) { @@ -2113,14 +2172,14 @@ WriteLiteral(" "); #line default #line hidden - #line 617 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 630 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Untrust Enrol", MVC.API.Device.UpdateAllowUnauthenticatedEnrol(Model.Device.SerialNumber, false.ToString(), true), "Device_Show_Device_Actions_UntrustEnrol_Button")); #line default #line hidden - #line 617 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 630 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -2182,7 +2241,7 @@ WriteLiteral(@"> "); - #line 653 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 666 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -2191,7 +2250,7 @@ WriteLiteral(@"> WriteLiteral(" "); - #line 654 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 667 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanDecommission()) { @@ -2199,14 +2258,14 @@ WriteLiteral(" "); #line default #line hidden - #line 656 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 669 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Decommission", MVC.API.Device.Decommission(), "Device_Show_Device_Actions_Decommission_Button")); #line default #line hidden - #line 656 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 669 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -2238,13 +2297,13 @@ WriteLiteral(" class=\"none\""); WriteLiteral(">\r\n"); - #line 663 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 676 "..\..\Views\Device\DeviceParts\_Subject.cshtml" #line default #line hidden - #line 663 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 676 "..\..\Views\Device\DeviceParts\_Subject.cshtml" foreach (Device.DecommissionReasons decommissionReason in Enum.GetValues(typeof(Device.DecommissionReasons))) { @@ -2255,34 +2314,34 @@ WriteLiteral("
  • \r\n WriteLiteral(" type=\"radio\""); -WriteAttribute("id", Tuple.Create(" id=\"", 41139), Tuple.Create("\"", 41217) -, Tuple.Create(Tuple.Create("", 41144), Tuple.Create("Device_Show_Device_Actions_Decommission_Reason_", 41144), true) +WriteAttribute("id", Tuple.Create(" id=\"", 41935), Tuple.Create("\"", 42013) +, Tuple.Create(Tuple.Create("", 41940), Tuple.Create("Device_Show_Device_Actions_Decommission_Reason_", 41940), true) - #line 666 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 41191), Tuple.Create((int)decommissionReason + #line 679 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 41987), Tuple.Create((int)decommissionReason #line default #line hidden -, 41191), false) +, 41987), false) ); WriteLiteral("\r\n name=\"Device_Show_Device_Actions_Decomm" + "ission_Reason\""); -WriteAttribute("value", Tuple.Create(" value=\"", 41313), Tuple.Create("\"", 41347) +WriteAttribute("value", Tuple.Create(" value=\"", 42109), Tuple.Create("\"", 42143) - #line 667 "..\..\Views\Device\DeviceParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 41321), Tuple.Create((int)decommissionReason + #line 680 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 42117), Tuple.Create((int)decommissionReason #line default #line hidden -, 41321), false) +, 42117), false) ); WriteLiteral(" "); - #line 667 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 680 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write((decommissionReason == Device.DecommissionReasons.EndOfLife) ? "checked=\"checked\"" : string.Empty); @@ -2290,21 +2349,21 @@ WriteLiteral(" "); #line hidden WriteLiteral("/>\r\n ((int)decommissionReason + #line 681 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + , Tuple.Create(Tuple.Create("", 42346), Tuple.Create((int)decommissionReason #line default #line hidden -, 41550), false) +, 42346), false) ); WriteLiteral(">"); - #line 668 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 681 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(decommissionReason.ReasonMessage()); @@ -2313,7 +2372,7 @@ WriteLiteral(">"); WriteLiteral("\r\n
  • \r\n"); - #line 670 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 683 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -2331,7 +2390,7 @@ WriteLiteral(">\r\n $(function () {\r\n "uttonDialog = null;\r\n var deviceSerialNumber = \'"); - #line 678 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 691 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Model.Device.SerialNumber); @@ -2364,7 +2423,7 @@ WriteLiteral("\';\r\n\r\n button.click(function () {\r\n\ " });\r\n \r\n"); - #line 714 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 727 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -2373,7 +2432,7 @@ WriteLiteral("\';\r\n\r\n button.click(function () {\r\n\ WriteLiteral(" "); - #line 715 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 728 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanRecommission()) { @@ -2381,14 +2440,14 @@ WriteLiteral(" "); #line default #line hidden - #line 717 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 730 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Recommission", MVC.API.Device.Recommission(Model.Device.SerialNumber, true), "Device_Show_Device_Actions_Recommission_Button")); #line default #line hidden - #line 717 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 730 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -2442,7 +2501,7 @@ WriteLiteral(@"> "); - #line 752 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 765 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } @@ -2451,7 +2510,7 @@ WriteLiteral(@"> WriteLiteral(" "); - #line 753 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 766 "..\..\Views\Device\DeviceParts\_Subject.cshtml" if (Model.Device.CanDelete()) { @@ -2459,14 +2518,14 @@ WriteLiteral(" "); #line default #line hidden - #line 755 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 768 "..\..\Views\Device\DeviceParts\_Subject.cshtml" Write(Html.ActionLinkSmallButton("Delete Device", MVC.API.Device.Delete(Model.Device.SerialNumber, true), "Device_Show_Device_Actions_Delete_Button")); #line default #line hidden - #line 755 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 768 "..\..\Views\Device\DeviceParts\_Subject.cshtml" @@ -2526,7 +2585,7 @@ WriteLiteral(@"> "); - #line 793 "..\..\Views\Device\DeviceParts\_Subject.cshtml" + #line 806 "..\..\Views\Device\DeviceParts\_Subject.cshtml" } diff --git a/Disco.Web/Views/Device/ImportExport.generated.cs b/Disco.Web/Views/Device/ImportExport.generated.cs index 16365e56..e47f6bba 100644 --- a/Disco.Web/Views/Device/ImportExport.generated.cs +++ b/Disco.Web/Views/Device/ImportExport.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/ImportReview.generated.cs b/Disco.Web/Views/Device/ImportReview.generated.cs index 8cdac7ce..ca3dc7ac 100644 --- a/Disco.Web/Views/Device/ImportReview.generated.cs +++ b/Disco.Web/Views/Device/ImportReview.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -35,6 +35,7 @@ namespace Disco.Web.Views.Device #line hidden using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/Index.generated.cs b/Disco.Web/Views/Device/Index.generated.cs index eaffe221..79a67761 100644 --- a/Disco.Web/Views/Device/Index.generated.cs +++ b/Disco.Web/Views/Device/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/Show.generated.cs b/Disco.Web/Views/Device/Show.generated.cs index ed4d2fc8..e9776396 100644 --- a/Disco.Web/Views/Device/Show.generated.cs +++ b/Disco.Web/Views/Device/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Device/_DeviceTable.generated.cs b/Disco.Web/Views/Device/_DeviceTable.generated.cs index 4e78592d..1965947a 100644 --- a/Disco.Web/Views/Device/_DeviceTable.generated.cs +++ b/Disco.Web/Views/Device/_DeviceTable.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Device/_ViewStart.generated.cs b/Disco.Web/Views/Device/_ViewStart.generated.cs index a6645d8e..f2e8d1f2 100644 --- a/Disco.Web/Views/Device/_ViewStart.generated.cs +++ b/Disco.Web/Views/Device/_ViewStart.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Device using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/Complete.generated.cs b/Disco.Web/Views/InitialConfig/Complete.generated.cs index 946da4fa..76a43c03 100644 --- a/Disco.Web/Views/InitialConfig/Complete.generated.cs +++ b/Disco.Web/Views/InitialConfig/Complete.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/Database.generated.cs b/Disco.Web/Views/InitialConfig/Database.generated.cs index 85027acc..87659dc9 100644 --- a/Disco.Web/Views/InitialConfig/Database.generated.cs +++ b/Disco.Web/Views/InitialConfig/Database.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/FileStore.generated.cs b/Disco.Web/Views/InitialConfig/FileStore.generated.cs index 79bfbbad..1044ac5f 100644 --- a/Disco.Web/Views/InitialConfig/FileStore.generated.cs +++ b/Disco.Web/Views/InitialConfig/FileStore.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/RestartWebApp.generated.cs b/Disco.Web/Views/InitialConfig/RestartWebApp.generated.cs index 61d93656..e468190a 100644 --- a/Disco.Web/Views/InitialConfig/RestartWebApp.generated.cs +++ b/Disco.Web/Views/InitialConfig/RestartWebApp.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/Welcome.generated.cs b/Disco.Web/Views/InitialConfig/Welcome.generated.cs index 42d5bb89..9d3f9ec2 100644 --- a/Disco.Web/Views/InitialConfig/Welcome.generated.cs +++ b/Disco.Web/Views/InitialConfig/Welcome.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/_Layout.generated.cs b/Disco.Web/Views/InitialConfig/_Layout.generated.cs index 887cfaca..00ab82ef 100644 --- a/Disco.Web/Views/InitialConfig/_Layout.generated.cs +++ b/Disco.Web/Views/InitialConfig/_Layout.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/InitialConfig/_ViewStart.generated.cs b/Disco.Web/Views/InitialConfig/_ViewStart.generated.cs index d6de9fba..ef9f3270 100644 --- a/Disco.Web/Views/InitialConfig/_ViewStart.generated.cs +++ b/Disco.Web/Views/InitialConfig/_ViewStart.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.InitialConfig using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/JobParts/Components.generated.cs b/Disco.Web/Views/Job/JobParts/Components.generated.cs index 0dae94ea..0f1d356f 100644 --- a/Disco.Web/Views/Job/JobParts/Components.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Components.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job.JobParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/JobParts/Flags.generated.cs b/Disco.Web/Views/Job/JobParts/Flags.generated.cs index ab454666..43ae414e 100644 --- a/Disco.Web/Views/Job/JobParts/Flags.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Flags.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/Insurance.generated.cs b/Disco.Web/Views/Job/JobParts/Insurance.generated.cs index ee39d264..95f64a52 100644 --- a/Disco.Web/Views/Job/JobParts/Insurance.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Insurance.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/JobMetaAdditions1.generated.cs b/Disco.Web/Views/Job/JobParts/JobMetaAdditions1.generated.cs index 36172c02..247285ab 100644 --- a/Disco.Web/Views/Job/JobParts/JobMetaAdditions1.generated.cs +++ b/Disco.Web/Views/Job/JobParts/JobMetaAdditions1.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -34,6 +34,7 @@ namespace Disco.Web.Views.Job.JobParts #line default #line hidden + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/JobParts/NonWarranty.generated.cs b/Disco.Web/Views/Job/JobParts/NonWarranty.generated.cs index 8d4618f2..59e4fbd3 100644 --- a/Disco.Web/Views/Job/JobParts/NonWarranty.generated.cs +++ b/Disco.Web/Views/Job/JobParts/NonWarranty.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/NonWarrantyFinance.generated.cs b/Disco.Web/Views/Job/JobParts/NonWarrantyFinance.generated.cs index 376aaf53..0246b9eb 100644 --- a/Disco.Web/Views/Job/JobParts/NonWarrantyFinance.generated.cs +++ b/Disco.Web/Views/Job/JobParts/NonWarrantyFinance.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/Queues.generated.cs b/Disco.Web/Views/Job/JobParts/Queues.generated.cs index 370623b6..951534db 100644 --- a/Disco.Web/Views/Job/JobParts/Queues.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Queues.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/Repairs.generated.cs b/Disco.Web/Views/Job/JobParts/Repairs.generated.cs index 1a9d8319..41f7daa6 100644 --- a/Disco.Web/Views/Job/JobParts/Repairs.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Repairs.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/JobParts/Resources.cshtml b/Disco.Web/Views/Job/JobParts/Resources.cshtml index a0b9af80..07730ddb 100644 --- a/Disco.Web/Views/Job/JobParts/Resources.cshtml +++ b/Disco.Web/Views/Job/JobParts/Resources.cshtml @@ -29,7 +29,7 @@ @foreach (var jl in Model.Job.JobLogs.OrderBy(m => m.Timestamp)) {
    - @jl.TechUser.ToString()@if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.Id)) + @jl.TechUser.ToString()@if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.UserId)) {}@jl.Timestamp.ToFullDateTime() @jl.Comments.ToMultilineJobRefString()
    @@ -58,7 +58,7 @@ { @ja.DocumentTemplate.Description} else { @ja.Comments }} - @ja.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.Id)) + @ja.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.UserId)) {}@ja.Timestamp.ToFullDateTime() } @@ -230,7 +230,7 @@ @if (canRemoveAnyLogs) {addComment(d, false, true);} else if (canRemoveOwnLogs) - {addComment(d, false, (d.AuthorId === '@(CurrentUser.Id)'));} + {addComment(d, false, (d.AuthorId === '@(CurrentUser.UserId)'));} else {addComment(d, false, false);} @@ -447,7 +447,7 @@ } else if (canRemoveOwnAttachments) { - buildAttachment(a, (a.AuthorId === '@(CurrentUser.Id)'), quick); + buildAttachment(a, (a.AuthorId === '@(CurrentUser.UserId)'), quick); } else { diff --git a/Disco.Web/Views/Job/JobParts/Resources.generated.cs b/Disco.Web/Views/Job/JobParts/Resources.generated.cs index ffab507c..9015df31 100644 --- a/Disco.Web/Views/Job/JobParts/Resources.generated.cs +++ b/Disco.Web/Views/Job/JobParts/Resources.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -173,7 +173,7 @@ WriteLiteral(""); #line 32 "..\..\Views\Job\JobParts\Resources.cshtml" - if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.Id)) + if (canRemoveAnyLogs || (canRemoveOwnLogs && jl.TechUserId == CurrentUser.UserId)) { #line default @@ -205,14 +205,14 @@ WriteLiteral(" data-livestamp=\""); #line hidden WriteLiteral("\""); -WriteAttribute("title", Tuple.Create(" title=\"", 1877), Tuple.Create("\"", 1915) +WriteAttribute("title", Tuple.Create(" title=\"", 1881), Tuple.Create("\"", 1919) #line 33 "..\..\Views\Job\JobParts\Resources.cshtml" - , Tuple.Create(Tuple.Create("", 1885), Tuple.Create(jl.Timestamp.ToFullDateTime() + , Tuple.Create(Tuple.Create("", 1889), Tuple.Create(jl.Timestamp.ToFullDateTime() #line default #line hidden -, 1885), false) +, 1889), false) ); WriteLiteral(">"); @@ -312,14 +312,14 @@ WriteLiteral(" (canAddAttachments ? "canAddAttachments" : "cannotAddAttachments" +, Tuple.Create(Tuple.Create("", 2632), Tuple.Create(canAddAttachments ? "canAddAttachments" : "cannotAddAttachments" #line default #line hidden -, 2628), false) +, 2632), false) ); WriteLiteral(">\r\n \r\n"); #line hidden WriteLiteral(" (Url.Action(MVC.API.Job.AttachmentDownload(ja.Id)) +, Tuple.Create(Tuple.Create("", 2874), Tuple.Create(Url.Action(MVC.API.Job.AttachmentDownload(ja.Id)) #line default #line hidden -, 2870), false) +, 2874), false) ); WriteLiteral(" data-attachmentid=\""); @@ -380,42 +380,42 @@ WriteLiteral(">\r\n (ja.Filename +, Tuple.Create(Tuple.Create("", 3038), Tuple.Create(ja.Filename #line default #line hidden -, 3034), false) +, 3038), false) ); WriteLiteral(">\r\n (Url.Action(MVC.API.Job.AttachmentThumbnail(ja.Id)) +, Tuple.Create(Tuple.Create("", 3123), Tuple.Create(Url.Action(MVC.API.Job.AttachmentThumbnail(ja.Id)) #line default #line hidden -, 3119), false) +, 3123), false) ); WriteLiteral(" />\r\n (ja.Comments +, Tuple.Create(Tuple.Create("", 3247), Tuple.Create(ja.Comments #line default #line hidden -, 3243), false) +, 3247), false) ); WriteLiteral(">\r\n"); @@ -478,7 +478,7 @@ WriteLiteral(""); #line 61 "..\..\Views\Job\JobParts\Resources.cshtml" - if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.Id)) + if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ja.TechUserId == CurrentUser.UserId)) { #line default @@ -510,14 +510,14 @@ WriteLiteral(" data-livestamp=\""); #line hidden WriteLiteral("\""); -WriteAttribute("title", Tuple.Create(" title=\"", 3906), Tuple.Create("\"", 3944) +WriteAttribute("title", Tuple.Create(" title=\"", 3914), Tuple.Create("\"", 3952) #line 62 "..\..\Views\Job\JobParts\Resources.cshtml" - , Tuple.Create(Tuple.Create("", 3914), Tuple.Create(ja.Timestamp.ToFullDateTime() + , Tuple.Create(Tuple.Create("", 3922), Tuple.Create(ja.Timestamp.ToFullDateTime() #line default #line hidden -, 3914), false) +, 3922), false) ); WriteLiteral(">"); @@ -907,7 +907,7 @@ WriteLiteral("addComment(d, false, (d.AuthorId === \'"); #line 233 "..\..\Views\Job\JobParts\Resources.cshtml" - Write(CurrentUser.Id); + Write(CurrentUser.UserId); #line default @@ -916,7 +916,7 @@ WriteLiteral("\'));"); #line 233 "..\..\Views\Job\JobParts\Resources.cshtml" - } + } else { @@ -1250,7 +1250,7 @@ WriteLiteral("buildAttachment(a, (a.AuthorId === \'"); #line 450 "..\..\Views\Job\JobParts\Resources.cshtml" - Write(CurrentUser.Id); + Write(CurrentUser.UserId); #line default diff --git a/Disco.Web/Views/Job/JobParts/_Subject.cshtml b/Disco.Web/Views/Job/JobParts/_Subject.cshtml index 7a8dca2e..2250dad8 100644 --- a/Disco.Web/Views/Job/JobParts/_Subject.cshtml +++ b/Disco.Web/Views/Job/JobParts/_Subject.cshtml @@ -438,7 +438,7 @@ else {@Model.Job.User.DisplayName} -
    @Model.Job.UserId
    +
    @Model.Job.User.FriendlyId()
    @if (Authorization.Has(Claims.User.ShowDetails)) { if (!string.IsNullOrWhiteSpace(Model.Job.User.PhoneNumber)) diff --git a/Disco.Web/Views/Job/JobParts/_Subject.generated.cs b/Disco.Web/Views/Job/JobParts/_Subject.generated.cs index 78e82a0c..0d84f697 100644 --- a/Disco.Web/Views/Job/JobParts/_Subject.generated.cs +++ b/Disco.Web/Views/Job/JobParts/_Subject.generated.cs @@ -753,7 +753,7 @@ WriteLiteral(">"); #line 192 "..\..\Views\Job\JobParts\_Subject.cshtml" - Write(Model.Job.Device.ComputerName); + Write(Model.Job.Device.DeviceDomainId); #line default @@ -1601,7 +1601,7 @@ WriteLiteral(">"); #line 441 "..\..\Views\Job\JobParts\_Subject.cshtml" - Write(Model.Job.UserId); + Write(Model.Job.User.FriendlyId()); #line default @@ -1656,15 +1656,15 @@ WriteLiteral(" title=\"Email Address\""); WriteLiteral(">Email: (Model.Job.User.EmailAddress + , Tuple.Create(Tuple.Create("", 31604), Tuple.Create(Model.Job.User.EmailAddress #line default #line hidden -, 31593), false) +, 31604), false) ); WriteLiteral(">"); @@ -2152,14 +2152,14 @@ WriteLiteral(" type=\"hidden\""); WriteLiteral(" name=\"JobId\""); -WriteAttribute("value", Tuple.Create(" value=\"", 42282), Tuple.Create("\"", 42303) +WriteAttribute("value", Tuple.Create(" value=\"", 42293), Tuple.Create("\"", 42314) #line 645 "..\..\Views\Job\JobParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 42290), Tuple.Create(Model.Job.Id + , Tuple.Create(Tuple.Create("", 42301), Tuple.Create(Model.Job.Id #line default #line hidden -, 42290), false) +, 42301), false) ); WriteLiteral(" />\r\n"); @@ -2223,26 +2223,26 @@ WriteLiteral("\""); WriteLiteral(">\r\n (jobQueue.Icon +, Tuple.Create(Tuple.Create("", 42797), Tuple.Create(jobQueue.Icon #line default #line hidden -, 42786), false) -, Tuple.Create(Tuple.Create(" ", 42802), Tuple.Create("fa-fw", 42803), true) -, Tuple.Create(Tuple.Create(" ", 42808), Tuple.Create("fa-lg", 42809), true) -, Tuple.Create(Tuple.Create(" ", 42814), Tuple.Create("d-", 42815), true) +, 42797), false) +, Tuple.Create(Tuple.Create(" ", 42813), Tuple.Create("fa-fw", 42814), true) +, Tuple.Create(Tuple.Create(" ", 42819), Tuple.Create("fa-lg", 42820), true) +, Tuple.Create(Tuple.Create(" ", 42825), Tuple.Create("d-", 42826), true) #line 650 "..\..\Views\Job\JobParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 42817), Tuple.Create(jobQueue.IconColour + , Tuple.Create(Tuple.Create("", 42828), Tuple.Create(jobQueue.IconColour #line default #line hidden -, 42817), false) +, 42828), false) ); WriteLiteral(">"); @@ -2283,27 +2283,27 @@ WriteLiteral(" "); #line hidden WriteLiteral(" (priorityValue.ToLower() + , Tuple.Create(Tuple.Create("", 43214), Tuple.Create(priorityValue.ToLower() #line default #line hidden -, 43203), false) +, 43214), false) ); -WriteAttribute("title", Tuple.Create(" title=\"", 43230), Tuple.Create("\"", 43263) +WriteAttribute("title", Tuple.Create(" title=\"", 43241), Tuple.Create("\"", 43274) #line 657 "..\..\Views\Job\JobParts\_Subject.cshtml" - , Tuple.Create(Tuple.Create("", 43238), Tuple.Create(priorityValue + , Tuple.Create(Tuple.Create("", 43249), Tuple.Create(priorityValue #line default #line hidden -, 43238), false) -, Tuple.Create(Tuple.Create(" ", 43254), Tuple.Create("Priority", 43255), true) +, 43249), false) +, Tuple.Create(Tuple.Create(" ", 43265), Tuple.Create("Priority", 43266), true) ); WriteLiteral(">\r\n \r\n
    \r\n " + diff --git a/Disco.Web/Views/Job/List.generated.cs b/Disco.Web/Views/Job/List.generated.cs index 3889fbf5..8098fb1d 100644 --- a/Disco.Web/Views/Job/List.generated.cs +++ b/Disco.Web/Views/Job/List.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/LogWarranty.generated.cs b/Disco.Web/Views/Job/LogWarranty.generated.cs index 406c4cb7..d79b8134 100644 --- a/Disco.Web/Views/Job/LogWarranty.generated.cs +++ b/Disco.Web/Views/Job/LogWarranty.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/LogWarrantyDisclose.generated.cs b/Disco.Web/Views/Job/LogWarrantyDisclose.generated.cs index f747ea1a..59344403 100644 --- a/Disco.Web/Views/Job/LogWarrantyDisclose.generated.cs +++ b/Disco.Web/Views/Job/LogWarrantyDisclose.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/LogWarrantyError.generated.cs b/Disco.Web/Views/Job/LogWarrantyError.generated.cs index dd5b5b45..2c2e4de6 100644 --- a/Disco.Web/Views/Job/LogWarrantyError.generated.cs +++ b/Disco.Web/Views/Job/LogWarrantyError.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/Show.generated.cs b/Disco.Web/Views/Job/Show.generated.cs index f4420a39..3ae74c88 100644 --- a/Disco.Web/Views/Job/Show.generated.cs +++ b/Disco.Web/Views/Job/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Job/WarrantyProviderJobDetails.generated.cs b/Disco.Web/Views/Job/WarrantyProviderJobDetails.generated.cs index 22f9ca85..b187537b 100644 --- a/Disco.Web/Views/Job/WarrantyProviderJobDetails.generated.cs +++ b/Disco.Web/Views/Job/WarrantyProviderJobDetails.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Job/_CreateSubject.cshtml b/Disco.Web/Views/Job/_CreateSubject.cshtml index 08d6387d..f01f137e 100644 --- a/Disco.Web/Views/Job/_CreateSubject.cshtml +++ b/Disco.Web/Views/Job/_CreateSubject.cshtml @@ -35,7 +35,7 @@ } else { - Id: @Model.User.Id
    + Id: @Model.User.UserId
    Name: @Model.User.DisplayName } diff --git a/Disco.Web/Views/Job/_CreateSubject.generated.cs b/Disco.Web/Views/Job/_CreateSubject.generated.cs index 9c235993..5f1ab969 100644 --- a/Disco.Web/Views/Job/_CreateSubject.generated.cs +++ b/Disco.Web/Views/Job/_CreateSubject.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -148,7 +149,7 @@ WriteLiteral(" Name: "); #line 24 "..\..\Views\Job\_CreateSubject.cshtml" - Write(Model.Device.ComputerName); + Write(Model.Device.DeviceDomainId); #line default @@ -215,7 +216,7 @@ WriteLiteral(" Id: "); #line 38 "..\..\Views\Job\_CreateSubject.cshtml" - Write(Model.User.Id); + Write(Model.User.UserId); #line default diff --git a/Disco.Web/Views/Job/_ViewStart.generated.cs b/Disco.Web/Views/Job/_ViewStart.generated.cs index d768db35..b481bf88 100644 --- a/Disco.Web/Views/Job/_ViewStart.generated.cs +++ b/Disco.Web/Views/Job/_ViewStart.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Job using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Search/Query.generated.cs b/Disco.Web/Views/Search/Query.generated.cs index 38dff63e..9a127c3b 100644 --- a/Disco.Web/Views/Search/Query.generated.cs +++ b/Disco.Web/Views/Search/Query.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Search using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Shared/DisplayTemplates/AccessDeniedException.generated.cs b/Disco.Web/Views/Shared/DisplayTemplates/AccessDeniedException.generated.cs index cc477816..a8cf496e 100644 --- a/Disco.Web/Views/Shared/DisplayTemplates/AccessDeniedException.generated.cs +++ b/Disco.Web/Views/Shared/DisplayTemplates/AccessDeniedException.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared.DisplayTemplates using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -36,9 +37,9 @@ namespace Disco.Web.Views.Shared.DisplayTemplates [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] [System.Web.WebPages.PageVirtualPathAttribute("~/Views/Shared/DisplayTemplates/AccessDeniedException.cshtml")] - public partial class AccessDeniedException : Disco.Services.Web.WebViewPage + public partial class _AccessDeniedException : Disco.Services.Web.WebViewPage { - public AccessDeniedException() + public _AccessDeniedException() { } public override void Execute() diff --git a/Disco.Web/Views/Shared/DisplayTemplates/Exception.generated.cs b/Disco.Web/Views/Shared/DisplayTemplates/Exception.generated.cs index b9112eb8..9a27e018 100644 --- a/Disco.Web/Views/Shared/DisplayTemplates/Exception.generated.cs +++ b/Disco.Web/Views/Shared/DisplayTemplates/Exception.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared.DisplayTemplates using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -36,9 +37,9 @@ namespace Disco.Web.Views.Shared.DisplayTemplates [System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")] [System.Web.WebPages.PageVirtualPathAttribute("~/Views/Shared/DisplayTemplates/Exception.cshtml")] - public partial class Exception : Disco.Services.Web.WebViewPage + public partial class _Exception : Disco.Services.Web.WebViewPage { - public Exception() + public _Exception() { } public override void Execute() diff --git a/Disco.Web/Views/Shared/Error.generated.cs b/Disco.Web/Views/Shared/Error.generated.cs index 15ebcfc6..d2f2a3cc 100644 --- a/Disco.Web/Views/Shared/Error.generated.cs +++ b/Disco.Web/Views/Shared/Error.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Shared/_DialogLayout.generated.cs b/Disco.Web/Views/Shared/_DialogLayout.generated.cs index 8007beff..03b588a6 100644 --- a/Disco.Web/Views/Shared/_DialogLayout.generated.cs +++ b/Disco.Web/Views/Shared/_DialogLayout.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Shared/_EmptyLayout.generated.cs b/Disco.Web/Views/Shared/_EmptyLayout.generated.cs index 55a8b3b5..64c46638 100644 --- a/Disco.Web/Views/Shared/_EmptyLayout.generated.cs +++ b/Disco.Web/Views/Shared/_EmptyLayout.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Shared/_JobTable.generated.cs b/Disco.Web/Views/Shared/_JobTable.generated.cs index 75d88836..76cb390a 100644 --- a/Disco.Web/Views/Shared/_JobTable.generated.cs +++ b/Disco.Web/Views/Shared/_JobTable.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. diff --git a/Disco.Web/Views/Shared/_JobTableRender.cshtml b/Disco.Web/Views/Shared/_JobTableRender.cshtml index d75b4eb2..19e6dfc0 100644 --- a/Disco.Web/Views/Shared/_JobTableRender.cshtml +++ b/Disco.Web/Views/Shared/_JobTableRender.cshtml @@ -102,14 +102,14 @@ @if (item.UserId != null) { if (Authorization.Has(Claims.User.Show)) - {@Html.ActionLink(string.Format("{0} ({1})", item.UserDisplayName, item.UserId), MVC.User.Show(item.UserId))} + {@Html.ActionLink(string.Format("{0} ({1})", item.UserDisplayName, item.UserFriendlyId), MVC.User.Show(item.UserId))} else - {@(string.Format("{0} ({1})", item.UserDisplayName, item.UserId))} + {@(string.Format("{0} ({1})", item.UserDisplayName, item.UserFriendlyId))} } else {N/A}} @if (Model.ShowTechnician) - {@item.OpenedTechUserId} + {@item.OpenedTechUserFriendlyId} @if (Model.ShowLocation) {@(item.DeviceHeldLocation ?? "Unknown")} } diff --git a/Disco.Web/Views/Shared/_JobTableRender.generated.cs b/Disco.Web/Views/Shared/_JobTableRender.generated.cs index 2d5b2342..22dfb24d 100644 --- a/Disco.Web/Views/Shared/_JobTableRender.generated.cs +++ b/Disco.Web/Views/Shared/_JobTableRender.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -860,14 +860,14 @@ WriteLiteral(">\r\n"); #line hidden #line 105 "..\..\Views\Shared\_JobTableRender.cshtml" - Write(Html.ActionLink(string.Format("{0} ({1})", item.UserDisplayName, item.UserId), MVC.User.Show(item.UserId))); + Write(Html.ActionLink(string.Format("{0} ({1})", item.UserDisplayName, item.UserFriendlyId), MVC.User.Show(item.UserId))); #line default #line hidden #line 105 "..\..\Views\Shared\_JobTableRender.cshtml" - } + } else { @@ -875,14 +875,14 @@ WriteLiteral(">\r\n"); #line hidden #line 107 "..\..\Views\Shared\_JobTableRender.cshtml" - Write(string.Format("{0} ({1})", item.UserDisplayName, item.UserId)); + Write(string.Format("{0} ({1})", item.UserDisplayName, item.UserFriendlyId)); #line default #line hidden #line 107 "..\..\Views\Shared\_JobTableRender.cshtml" - } + } } else { @@ -925,21 +925,21 @@ WriteLiteral(" class=\"technician\""); WriteLiteral(">(item.OpenedTechUserDisplayName +, Tuple.Create(Tuple.Create("", 6445), Tuple.Create(item.OpenedTechUserDisplayName #line default #line hidden -, 6429), false) +, 6445), false) ); WriteLiteral(">"); #line 112 "..\..\Views\Shared\_JobTableRender.cshtml" - Write(item.OpenedTechUserId); + Write(item.OpenedTechUserFriendlyId); #line default @@ -948,7 +948,7 @@ WriteLiteral(""); #line 112 "..\..\Views\Shared\_JobTableRender.cshtml" - } + } #line default diff --git a/Disco.Web/Views/Shared/_Layout.cshtml b/Disco.Web/Views/Shared/_Layout.cshtml index 7a0c12db..aaaf9796 100644 --- a/Disco.Web/Views/Shared/_Layout.cshtml +++ b/Disco.Web/Views/Shared/_Layout.cshtml @@ -123,7 +123,7 @@
    @if (Authorization.Has(Claims.User.Show)) - { @Html.ActionLink(CurrentUser.ToString(), MVC.User.Show(CurrentUser.Id))} + { @Html.ActionLink(CurrentUser.ToString(), MVC.User.Show(CurrentUser.UserId))} else {@CurrentUser.ToString()} @if (Authorization.HasAny(Claims.Job.Search, Claims.Device.Search, Claims.User.Search)) diff --git a/Disco.Web/Views/Shared/_Layout.generated.cs b/Disco.Web/Views/Shared/_Layout.generated.cs index d95b642e..6950cbcb 100644 --- a/Disco.Web/Views/Shared/_Layout.generated.cs +++ b/Disco.Web/Views/Shared/_Layout.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -870,14 +870,14 @@ WriteLiteral(">\r\n "); #line hidden #line 126 "..\..\Views\Shared\_Layout.cshtml" - Write(Html.ActionLink(CurrentUser.ToString(), MVC.User.Show(CurrentUser.Id))); + Write(Html.ActionLink(CurrentUser.ToString(), MVC.User.Show(CurrentUser.UserId))); #line default #line hidden #line 126 "..\..\Views\Shared\_Layout.cshtml" - } + } else { diff --git a/Disco.Web/Views/Shared/_PublicLayout.generated.cs b/Disco.Web/Views/Shared/_PublicLayout.generated.cs index 4dbbb523..22a388a0 100644 --- a/Disco.Web/Views/Shared/_PublicLayout.generated.cs +++ b/Disco.Web/Views/Shared/_PublicLayout.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Shared/_SearchDialog.generated.cs b/Disco.Web/Views/Shared/_SearchDialog.generated.cs index e92759af..26da4384 100644 --- a/Disco.Web/Views/Shared/_SearchDialog.generated.cs +++ b/Disco.Web/Views/Shared/_SearchDialog.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Shared using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/Update/Index.generated.cs b/Disco.Web/Views/Update/Index.generated.cs index aa309f7b..95cc258a 100644 --- a/Disco.Web/Views/Update/Index.generated.cs +++ b/Disco.Web/Views/Update/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.Update using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/User/Index.generated.cs b/Disco.Web/Views/User/Index.generated.cs index 713def96..b42c0c29 100644 --- a/Disco.Web/Views/User/Index.generated.cs +++ b/Disco.Web/Views/User/Index.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.User using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/User/Show.cshtml b/Disco.Web/Views/User/Show.cshtml index 7b1da0c1..6cfe0477 100644 --- a/Disco.Web/Views/User/Show.cshtml +++ b/Disco.Web/Views/User/Show.cshtml @@ -2,7 +2,7 @@ @{ Authorization.Require(Claims.User.Show); - ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.Id)); + ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId())); }
    @Html.Partial(MVC.User.Views.UserParts._Subject, Model) diff --git a/Disco.Web/Views/User/Show.generated.cs b/Disco.Web/Views/User/Show.generated.cs index 013bbfbe..84935e59 100644 --- a/Disco.Web/Views/User/Show.generated.cs +++ b/Disco.Web/Views/User/Show.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.User using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; @@ -48,7 +49,7 @@ namespace Disco.Web.Views.User Authorization.Require(Claims.User.Show); - ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.Id)); + ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId())); #line default diff --git a/Disco.Web/Views/User/UserParts/_AssignmentHistory.generated.cs b/Disco.Web/Views/User/UserParts/_AssignmentHistory.generated.cs index 850c01f0..c659bb58 100644 --- a/Disco.Web/Views/User/UserParts/_AssignmentHistory.generated.cs +++ b/Disco.Web/Views/User/UserParts/_AssignmentHistory.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.User.UserParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/User/UserParts/_Authorization.cshtml b/Disco.Web/Views/User/UserParts/_Authorization.cshtml index 36cc79b2..ffb96f67 100644 --- a/Disco.Web/Views/User/UserParts/_Authorization.cshtml +++ b/Disco.Web/Views/User/UserParts/_Authorization.cshtml @@ -38,7 +38,7 @@ {

    User Not Authorized

    -

    The user (@(Model.User.Id)) is not authorized to access any authenticated components.

    +

    The user (@(Model.User.UserId)) is not authorized to access any authenticated components.

    @if (isDiscoAdmin) { @Html.ActionLinkButton("Configure Authorization Roles", MVC.Config.AuthorizationRole.Index(null), null, "small") diff --git a/Disco.Web/Views/User/UserParts/_Authorization.generated.cs b/Disco.Web/Views/User/UserParts/_Authorization.generated.cs index 95a18404..1bbbcfd2 100644 --- a/Disco.Web/Views/User/UserParts/_Authorization.generated.cs +++ b/Disco.Web/Views/User/UserParts/_Authorization.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.User.UserParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; #line 2 "..\..\Views\User\UserParts\_Authorization.cshtml" @@ -148,7 +149,7 @@ WriteLiteral(">"); #line 41 "..\..\Views\User\UserParts\_Authorization.cshtml" - Write(Model.User.Id); + Write(Model.User.UserId); #line default diff --git a/Disco.Web/Views/User/UserParts/_Jobs.generated.cs b/Disco.Web/Views/User/UserParts/_Jobs.generated.cs index d380ff7a..ed354c60 100644 --- a/Disco.Web/Views/User/UserParts/_Jobs.generated.cs +++ b/Disco.Web/Views/User/UserParts/_Jobs.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -29,6 +29,7 @@ namespace Disco.Web.Views.User.UserParts using Disco; using Disco.BI.Extensions; using Disco.Models.Repository; + using Disco.Services; using Disco.Services.Authorization; using Disco.Services.Web; using Disco.Web; diff --git a/Disco.Web/Views/User/UserParts/_Resources.cshtml b/Disco.Web/Views/User/UserParts/_Resources.cshtml index 597c3942..864bcb51 100644 --- a/Disco.Web/Views/User/UserParts/_Resources.cshtml +++ b/Disco.Web/Views/User/UserParts/_Resources.cshtml @@ -31,7 +31,7 @@ { @ua.DocumentTemplate.Description} else { @ua.Comments }} - @ua.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId == CurrentUser.Id)) + @ua.TechUser.ToString()@if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId == CurrentUser.UserId)) {}@ua.Timestamp.ToFullDateTime() } @@ -87,7 +87,7 @@ } } }, - 'UploadUrl=@(Url.Action(MVC.API.User.AttachmentUpload(Model.User.Id, null)))' + 'UploadUrl=@(Url.Action(MVC.API.User.AttachmentUpload(Model.User.UserId, null)))' ); $attachmentInput = $Attachments.find('.attachmentInput'); @@ -122,7 +122,7 @@ } else if (canRemoveOwnAttachments) { - buildAttachment(a, (a.AuthorId === '@(CurrentUser.Id)'), quick); + buildAttachment(a, (a.AuthorId === '@(CurrentUser.UserId)'), quick); } else { diff --git a/Disco.Web/Views/User/UserParts/_Resources.generated.cs b/Disco.Web/Views/User/UserParts/_Resources.generated.cs index 224a87e7..82a89bf1 100644 --- a/Disco.Web/Views/User/UserParts/_Resources.generated.cs +++ b/Disco.Web/Views/User/UserParts/_Resources.generated.cs @@ -2,7 +2,7 @@ //------------------------------------------------------------------------------ // // This code was generated by a tool. -// Runtime Version:4.0.30319.34003 +// Runtime Version:4.0.30319.34011 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. @@ -246,7 +246,7 @@ WriteLiteral(""); #line 34 "..\..\Views\User\UserParts\_Resources.cshtml" - if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId == CurrentUser.Id)) + if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId == CurrentUser.UserId)) { #line default @@ -278,14 +278,14 @@ WriteLiteral(" data-livestamp=\""); #line hidden WriteLiteral("\""); -WriteAttribute("title", Tuple.Create(" title=\"", 2160), Tuple.Create("\"", 2198) +WriteAttribute("title", Tuple.Create(" title=\"", 2164), Tuple.Create("\"", 2202) #line 35 "..\..\Views\User\UserParts\_Resources.cshtml" - , Tuple.Create(Tuple.Create("", 2168), Tuple.Create(ua.Timestamp.ToFullDateTime() + , Tuple.Create(Tuple.Create("", 2172), Tuple.Create(ua.Timestamp.ToFullDateTime() #line default #line hidden -, 2168), false) +, 2172), false) ); WriteLiteral(">"); @@ -423,7 +423,7 @@ WriteLiteral(@"', #line 90 "..\..\Views\User\UserParts\_Resources.cshtml" - Write(Url.Action(MVC.API.User.AttachmentUpload(Model.User.Id, null))); + Write(Url.Action(MVC.API.User.AttachmentUpload(Model.User.UserId, null))); #line default @@ -503,7 +503,7 @@ WriteLiteral("buildAttachment(a, (a.AuthorId === \'"); #line 125 "..\..\Views\User\UserParts\_Resources.cshtml" - Write(CurrentUser.Id); + Write(CurrentUser.UserId); #line default diff --git a/Disco.Web/Views/User/UserParts/_Subject.cshtml b/Disco.Web/Views/User/UserParts/_Subject.cshtml index 51721b5f..3c4ec70f 100644 --- a/Disco.Web/Views/User/UserParts/_Subject.cshtml +++ b/Disco.Web/Views/User/UserParts/_Subject.cshtml @@ -15,7 +15,7 @@ Username (Id): -

    @Model.User.Id

    +

    @Model.User.UserId

    @@ -71,7 +71,7 @@ @Html.DropDownList("User_Show_GenerateDocument", Model.DocumentTemplatesSelectListItems)