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.Users.UserFlags { public class UserFlagUserDevicesManagedGroup : ADManagedGroup { private const string KeyFormat = "UserFlag_{0}_UserDevices"; private const string DescriptionFormat = "User associated with the {0} Flag will have their assigned Devices added to this Active Directory group."; private const string CategoryDescriptionFormat = "Assigned User Devices Linked Group"; private const string GroupDescriptionFormat = "{0} [User Flag User Devices]"; private IDisposable repositorySubscription; private int UserFlagId; private string UserFlagName; public override string Description { get { return string.Format(DescriptionFormat, UserFlagName); } } public override string CategoryDescription { get { return CategoryDescriptionFormat; } } public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, UserFlagName); } } public override bool IncludeFilterBeginDate { get { return true; } } private UserFlagUserDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, UserFlag UserFlag) : base(Key, Configuration) { UserFlagId = UserFlag.Id; UserFlagName = UserFlag.Name; } public override void Initialize() { // Subscribe to changes repositorySubscription = UserFlagService.UserFlagAssignmentRepositoryEvents.Value .Where(e => (((UserFlagAssignment)e.Entity).UserFlagId == UserFlagId)) .Subscribe(ProcessRepositoryEvent); } public static string GetKey(UserFlag UserFlag) { return string.Format(KeyFormat, UserFlag.Id); } public static string GetDescription(UserFlag UserFlag) { return string.Format(DescriptionFormat, UserFlag.Name); } public static string GetCategoryDescription(UserFlag UserFlag) { return CategoryDescriptionFormat; } public static bool TryGetManagedGroup(UserFlag UserFlag, out UserFlagUserDevicesManagedGroup ManagedGroup) { ADManagedGroup managedGroup; string key = GetKey(UserFlag); if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup)) { ManagedGroup = (UserFlagUserDevicesManagedGroup)managedGroup; return true; } else { ManagedGroup = null; return false; } } public static UserFlagUserDevicesManagedGroup Initialize(UserFlag UserFlag) { if (UserFlag.Id > 0) { var key = GetKey(UserFlag); if (!string.IsNullOrEmpty(UserFlag.UserDevicesLinkedGroup)) { var config = ADManagedGroup.ConfigurationFromJson(UserFlag.UserDevicesLinkedGroup); if (config != null && !string.IsNullOrWhiteSpace(config.GroupId)) { var group = new UserFlagUserDevicesManagedGroup( key, config, UserFlag); // Add to AD Context ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group); return group; } } // Remove from AD Context ActiveDirectory.Context.ManagedGroups.Remove(key); } return null; } private IEnumerable DetermineDeviceMembers(DiscoDataContext Database, string UserId) { IQueryable assignments; if (Configuration.FilterBeginDate.HasValue) { assignments = Database.Users .Where(u => u.UserId == UserId && u.UserFlagAssignments .Any(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue && a.AddedDate >= Configuration.FilterBeginDate)); } else { assignments = Database.Users .Where(u => u.UserId == UserId && u.UserFlagAssignments .Any(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue)); } return DetermineDeviceMembers(assignments); } private IEnumerable DetermineDeviceMembers(IQueryable Users) { return Users .SelectMany(u => u.DeviceUserAssignments) .Where(da => !da.UnassignedDate.HasValue && da.Device.DeviceDomainId != null) .Select(da => da.Device.DeviceDomainId) .ToList() .Where(ActiveDirectory.IsValidDomainAccountId) .Select(id => id + "$"); } public override IEnumerable DetermineMembers(DiscoDataContext Database) { IQueryable assignments; if (Configuration.FilterBeginDate.HasValue) { assignments = Database.UserFlagAssignments .Where(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue && a.AddedDate >= Configuration.FilterBeginDate) .Select(a => a.User); } else { assignments = Database.UserFlagAssignments .Where(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue) .Select(a => a.User); } return DetermineDeviceMembers(assignments); } private void ProcessRepositoryEvent(RepositoryMonitorEvent Event) { var userFlagAssignment = (UserFlagAssignment)Event.Entity; string userId = userFlagAssignment.UserId; switch (Event.EventType) { case RepositoryMonitorEventType.Added: if (Configuration.FilterBeginDate.HasValue) { if (!userFlagAssignment.RemovedDate.HasValue && userFlagAssignment.AddedDate >= Configuration.FilterBeginDate) { AddMember(userFlagAssignment.UserId, (database) => DetermineDeviceMembers(database, userId)); } } else { if (!userFlagAssignment.RemovedDate.HasValue) { AddMember(userFlagAssignment.UserId, (database) => DetermineDeviceMembers(database, userId)); } } break; case RepositoryMonitorEventType.Modified: if (!Configuration.FilterBeginDate.HasValue || userFlagAssignment.AddedDate >= Configuration.FilterBeginDate) { if (userFlagAssignment.RemovedDate.HasValue) RemoveMember(userFlagAssignment.UserId, (database) => DetermineDeviceMembers(database, userId)); else AddMember(userFlagAssignment.UserId, (database) => DetermineDeviceMembers(database, userId)); } break; case RepositoryMonitorEventType.Deleted: // Remove the user's devices if no other (non-removed) assignments exist. RemoveMember(userId, (database) => { if (Configuration.FilterBeginDate.HasValue) { if (database.UserFlagAssignments.Any(a => a.UserFlagId == UserFlagId && a.UserId == userId && !a.RemovedDate.HasValue && a.AddedDate >= Configuration.FilterBeginDate)) { return null; } else { return DetermineDeviceMembers(database, userId); } } else { if (database.UserFlagAssignments.Any(a => a.UserFlagId == UserFlagId && a.UserId == userId && !a.RemovedDate.HasValue)) { return null; } else { return DetermineDeviceMembers(database, userId); } } }); break; } } public override void Dispose() { if (repositorySubscription != null) repositorySubscription.Dispose(); } } }