using Disco.Data.Repository; using Disco.Data.Repository.Monitor; using Disco.Models.Repository; using Disco.Models.Services.Interop.ActiveDirectory; using Disco.Services.Interop.ActiveDirectory; using System; using System.Collections.Generic; using System.Linq; using System.Reactive.Linq; namespace Disco.Services.Devices.ManagedGroups { public class DeviceProfileDevicesManagedGroup : ADManagedGroup { private const string KeyFormat = "DeviceProfile_{0}_Devices"; private const string DescriptionFormat = "Devices within the {0} Profile will be added to this Active Directory group."; private const string CategoryDescriptionFormat = "Devices Linked Group"; private const string GroupDescriptionFormat = "{0} [Device Profile Devices]"; private static Lazy> RepositoryEvents; private IDisposable repositorySubscription; private int DeviceProfileId; private string DeviceProfileName; public override string Description { get { return string.Format(DescriptionFormat, DeviceProfileName); } } public override string CategoryDescription { get { return CategoryDescriptionFormat; } } public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DeviceProfileName); } } public override bool IncludeFilterBeginDate { get { return false; } } static DeviceProfileDevicesManagedGroup() { RepositoryEvents = new Lazy>(() => RepositoryMonitor.StreamBeforeCommit.Where(e => e.EntityType == typeof(Device) && ( (e.EventType == RepositoryMonitorEventType.Added && ActiveDirectory.IsValidDomainAccountId(((Device)e.Entity).DeviceDomainId)) || (e.EventType == RepositoryMonitorEventType.Modified && (e.ModifiedProperties.Contains("DeviceProfileId") || e.ModifiedProperties.Contains("DeviceDomainId") || e.ModifiedProperties.Contains("LastEnrolDate"))) || (e.EventType == RepositoryMonitorEventType.Deleted) ) )); } private DeviceProfileDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DeviceProfile DeviceProfile) : base(Key, Configuration) { DeviceProfileId = DeviceProfile.Id; DeviceProfileName = DeviceProfile.Name; } public override void Initialize() { // Subscribe to changes repositorySubscription = RepositoryEvents.Value .Where(e => (((Device)e.Entity).DeviceProfileId == DeviceProfileId) || (e.EventType == RepositoryMonitorEventType.Modified && e.GetPreviousPropertyValue("DeviceProfileId") == DeviceProfileId)) .Subscribe(ProcessRepositoryEvent); } public static string GetKey(DeviceProfile DeviceProfile) { return string.Format(KeyFormat, DeviceProfile.Id); } public static string GetDescription(DeviceProfile DeviceProfile) { return string.Format(DescriptionFormat, DeviceProfile.Name); } public static string GetCategoryDescription(DeviceProfile DeviceProfile) { return CategoryDescriptionFormat; } public static bool TryGetManagedGroup(DeviceProfile DeviceProfile, out DeviceProfileDevicesManagedGroup ManagedGroup) { ADManagedGroup managedGroup; string key = GetKey(DeviceProfile); if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup)) { ManagedGroup = (DeviceProfileDevicesManagedGroup)managedGroup; return true; } else { ManagedGroup = null; return false; } } public static DeviceProfileDevicesManagedGroup Initialize(DeviceProfile DeviceProfile) { if (DeviceProfile.Id > 0) { var key = GetKey(DeviceProfile); if (!string.IsNullOrEmpty(DeviceProfile.DevicesLinkedGroup)) { var config = ADManagedGroup.ConfigurationFromJson(DeviceProfile.DevicesLinkedGroup); if (config != null && !string.IsNullOrWhiteSpace(config.GroupId)) { var group = new DeviceProfileDevicesManagedGroup( key, config, DeviceProfile); // Add to AD Context ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group); return group; } } // Remove from AD Context ActiveDirectory.Context.ManagedGroups.Remove(key); } return null; } public override IEnumerable DetermineMembers(DiscoDataContext Database) { return Database.Devices .Where(d => d.DeviceProfileId == DeviceProfileId) .Where(d => d.DeviceDomainId != null) .Select(d => d.DeviceDomainId) .ToList() .Where(ActiveDirectory.IsValidDomainAccountId) .Select(id => id + "$"); } private void ProcessRepositoryEvent(RepositoryMonitorEvent Event) { var device = (Device)Event.Entity; string previousDeviceDomainId = Event.GetPreviousPropertyValue("DeviceDomainId"); Event.ExecuteAfterCommit(e => { switch (e.EventType) { case RepositoryMonitorEventType.Added: AddMember(device.DeviceDomainId + "$"); break; case RepositoryMonitorEventType.Modified: if (device.DeviceProfileId == DeviceProfileId) { if (ActiveDirectory.IsValidDomainAccountId(device.DeviceDomainId)) AddMember(device.DeviceDomainId + "$"); if (e.ModifiedProperties.Contains("DeviceDomainId")) { if (ActiveDirectory.IsValidDomainAccountId(previousDeviceDomainId)) RemoveMember(previousDeviceDomainId + "$"); } } else { if (e.ModifiedProperties.Contains("DeviceDomainId")) { if (ActiveDirectory.IsValidDomainAccountId(previousDeviceDomainId)) RemoveMember(previousDeviceDomainId + "$"); } else { if (ActiveDirectory.IsValidDomainAccountId(device.DeviceDomainId)) RemoveMember(device.DeviceDomainId + "$"); } } break; case RepositoryMonitorEventType.Deleted: if (ActiveDirectory.IsValidDomainAccountId(previousDeviceDomainId)) RemoveMember(previousDeviceDomainId + "$"); break; } }); } public override void Dispose() { if (repositorySubscription != null) repositorySubscription.Dispose(); } } }