a819d2722a
Document Template Attachments, Device Batches, Device Profiles and User Flags can be associated with an Active Directory group. This AD group is then automatically synchronized with relevant User/Machine accounts. Contains various other UI tweaks and configuration enhancements.
442 lines
20 KiB
C#
442 lines
20 KiB
C#
using Disco.Data.Repository;
|
|
using Disco.Data.Repository.Monitor;
|
|
using Disco.Models.Repository;
|
|
using Disco.Models.Services.Interop.ActiveDirectory;
|
|
using Disco.Services.Interop.ActiveDirectory;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reactive.Linq;
|
|
|
|
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
|
{
|
|
public class DocumentTemplateDevicesManagedGroup : ADManagedGroup
|
|
{
|
|
private const string KeyFormat = "DocumentTemplate_{0}_Devices";
|
|
private const string DeviceDescriptionFormat = "Devices with a {0} attachment will be added to this Active Directory group.";
|
|
private const string DescriptionFormat = "{0}s with a {1} attachment will have any associated devices added to this Active Directory group.";
|
|
private const string CategoryDescriptionFormat = "Related Devices Linked Group";
|
|
private const string GroupDescriptionFormat = "{0} [Document Template Devices]";
|
|
|
|
private IDisposable repositorySubscription;
|
|
private IDisposable deviceRenameRepositorySubscription;
|
|
private IDisposable jobCloseRepositorySubscription;
|
|
private IDisposable deviceAssignmentRepositorySubscription;
|
|
private string DocumentTemplateId;
|
|
private string DocumentTemplateDescription;
|
|
private string DocumentTemplateScope;
|
|
|
|
public override string Description { get { return GetDescription(DocumentTemplateScope, DocumentTemplateDescription); } }
|
|
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
|
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DocumentTemplateDescription); } }
|
|
public override bool IncludeFilterBeginDate { get { return true; } }
|
|
|
|
private DocumentTemplateDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DocumentTemplate DocumentTemplate)
|
|
: base(Key, Configuration)
|
|
{
|
|
this.DocumentTemplateId = DocumentTemplate.Id;
|
|
this.DocumentTemplateDescription = DocumentTemplate.Description;
|
|
this.DocumentTemplateScope = DocumentTemplate.Scope;
|
|
}
|
|
|
|
public override void Initialize()
|
|
{
|
|
// Subscribe to changes
|
|
switch (DocumentTemplateScope)
|
|
{
|
|
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
// Observe Device Attachments
|
|
repositorySubscription = DocumentTemplateManagedGroups.DeviceScopeRepositoryEvents.Value
|
|
.Where(e => ((DeviceAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
|
.Subscribe(ProcessDeviceRepositoryEvent);
|
|
break;
|
|
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
// Observe Job Attachments
|
|
repositorySubscription = DocumentTemplateManagedGroups.UserScopeRepositoryEvents.Value
|
|
.Where(e => ((JobAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
|
.Subscribe(ProcessJobRepositoryEvent);
|
|
// Observe Job Close/Reopen
|
|
jobCloseRepositorySubscription = DocumentTemplateManagedGroups.JobCloseRepositoryEvents.Value
|
|
.Subscribe(ProcessJobCloseRepositoryEvent);
|
|
break;
|
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
// Observe User Attachments
|
|
repositorySubscription = DocumentTemplateManagedGroups.UserScopeRepositoryEvents.Value
|
|
.Where(e => ((UserAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
|
.Subscribe(ProcessUserRepositoryEvent);
|
|
// Observe Device Assignments
|
|
deviceAssignmentRepositorySubscription = DocumentTemplateManagedGroups.DeviceAssignmentRepositoryEvents.Value
|
|
.Subscribe(ProcessDeviceAssignmentRepositoryEvent);
|
|
break;
|
|
}
|
|
|
|
// Observe Device Renaming (DeviceDomainId)
|
|
deviceRenameRepositorySubscription = DocumentTemplateManagedGroups.DeviceRenameRepositoryEvents.Value
|
|
.Subscribe(ProcessDeviceRenameRepositoryEvent);
|
|
}
|
|
|
|
public static string GetKey(DocumentTemplate DocumentTemplate)
|
|
{
|
|
return string.Format(KeyFormat, DocumentTemplate.Id);
|
|
}
|
|
private static string GetDescription(string DocumentTemplateScope, string DocumentTemplateDescription)
|
|
{
|
|
switch (DocumentTemplateScope)
|
|
{
|
|
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
return string.Format(DeviceDescriptionFormat, DocumentTemplateDescription);
|
|
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
return string.Format(DescriptionFormat, DocumentTemplateScope, DocumentTemplateDescription);
|
|
default:
|
|
throw new ArgumentException("Unknown Document Template Scope", "Scope");
|
|
}
|
|
}
|
|
public static string GetDescription(DocumentTemplate DocumentTemplate)
|
|
{
|
|
return GetDescription(DocumentTemplate.Scope, DocumentTemplate.Description);
|
|
}
|
|
public static string GetCategoryDescription(DocumentTemplate DocumentTemplate)
|
|
{
|
|
return CategoryDescriptionFormat;
|
|
}
|
|
|
|
public static bool TryGetManagedGroup(DocumentTemplate DocumentTemplate, out DocumentTemplateDevicesManagedGroup ManagedGroup)
|
|
{
|
|
ADManagedGroup managedGroup;
|
|
string key = GetKey(DocumentTemplate);
|
|
|
|
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
|
{
|
|
ManagedGroup = (DocumentTemplateDevicesManagedGroup)managedGroup;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
ManagedGroup = null;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static DocumentTemplateDevicesManagedGroup Initialize(DocumentTemplate Template)
|
|
{
|
|
var key = GetKey(Template);
|
|
|
|
if (!string.IsNullOrEmpty(Template.DevicesLinkedGroup))
|
|
{
|
|
var config = ADManagedGroup.ConfigurationFromJson(Template.DevicesLinkedGroup);
|
|
|
|
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
|
{
|
|
var group = new DocumentTemplateDevicesManagedGroup(
|
|
key,
|
|
config,
|
|
Template);
|
|
|
|
// Add to AD Context
|
|
ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group);
|
|
|
|
return group;
|
|
}
|
|
}
|
|
|
|
// Remove from AD Context
|
|
ActiveDirectory.Context.ManagedGroups.Remove(key);
|
|
|
|
return null;
|
|
}
|
|
|
|
public override IEnumerable<string> DetermineMembers(DiscoDataContext Database)
|
|
{
|
|
switch (DocumentTemplateScope)
|
|
{
|
|
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
return Database.Devices
|
|
.Where(d => d.DeviceDomainId != null && d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
|
.Select(d => d.DeviceDomainId)
|
|
.ToList()
|
|
.Where(ActiveDirectory.IsValidDomainAccountId)
|
|
.Select(id => id + "$");
|
|
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
return Database.Jobs
|
|
.Where(j => !j.ClosedDate.HasValue && j.Device.DeviceDomainId != null && j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
|
.Select(j => j.Device.DeviceDomainId)
|
|
.Distinct()
|
|
.ToList()
|
|
.Where(ActiveDirectory.IsValidDomainAccountId)
|
|
.Select(id => id + "$");
|
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
return Database.Users
|
|
.Where(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
|
.SelectMany(u => u.DeviceUserAssignments.Where(dua => !dua.UnassignedDate.HasValue && dua.Device.DeviceDomainId != null), (u, dua) => dua.Device.DeviceDomainId)
|
|
.ToList()
|
|
.Where(ActiveDirectory.IsValidDomainAccountId)
|
|
.Select(id => id + "$");
|
|
default:
|
|
return Enumerable.Empty<string>();
|
|
}
|
|
}
|
|
|
|
#region Device Scope
|
|
private bool DeviceContainsAttachment(DiscoDataContext Database, string DeviceSerialNumber, out string DeviceAccountId)
|
|
{
|
|
var result = Database.Devices
|
|
.Where(d => d.SerialNumber == DeviceSerialNumber && d.DeviceDomainId != null)
|
|
.Select(d => new Tuple<string, bool>(d.DeviceDomainId, d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
|
.FirstOrDefault();
|
|
|
|
if (result == null)
|
|
{
|
|
DeviceAccountId = null;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (ActiveDirectory.IsValidDomainAccountId(result.Item1))
|
|
{
|
|
DeviceAccountId = result.Item1 + "$";
|
|
return result.Item2;
|
|
}
|
|
else
|
|
{
|
|
DeviceAccountId = result.Item1 + "$";
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProcessDeviceRepositoryEvent(RepositoryMonitorEvent e)
|
|
{
|
|
var attachment = (DeviceAttachment)e.Entity;
|
|
|
|
string deviceAccountId;
|
|
if (DeviceContainsAttachment(e.Database, attachment.DeviceSerialNumber, out deviceAccountId))
|
|
AddMember(attachment.DeviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
else if (deviceAccountId != null)
|
|
RemoveMember(attachment.DeviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
}
|
|
#endregion
|
|
|
|
#region Job Scope
|
|
private bool JobsContainAttachment(DiscoDataContext Database, int JobId, out string DeviceAccountId, out string DeviceSerialNumber)
|
|
{
|
|
var result = Database.Jobs
|
|
.Where(j => j.Id == JobId && j.Device.DeviceDomainId != null)
|
|
.Select(j => new Tuple<string, string, bool>(
|
|
j.Device.DeviceDomainId,
|
|
j.Device.SerialNumber,
|
|
j.Device.Jobs.Where(dj => !dj.ClosedDate.HasValue).Any(dj => dj.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
|
).FirstOrDefault();
|
|
|
|
if (result == null)
|
|
{
|
|
DeviceAccountId = null;
|
|
DeviceSerialNumber = null;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if (ActiveDirectory.IsValidDomainAccountId(result.Item1))
|
|
{
|
|
DeviceAccountId = result.Item1 + "$";
|
|
DeviceSerialNumber = result.Item2;
|
|
return result.Item3;
|
|
}
|
|
else
|
|
{
|
|
DeviceAccountId = result.Item1 + "$";
|
|
DeviceSerialNumber = result.Item2;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProcessJobRepositoryEvent(RepositoryMonitorEvent e)
|
|
{
|
|
var attachment = (JobAttachment)e.Entity;
|
|
|
|
string deviceAccountId;
|
|
string deviceSerialNumber;
|
|
if (JobsContainAttachment(e.Database, attachment.JobId, out deviceAccountId, out deviceSerialNumber))
|
|
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
else if (deviceSerialNumber != null && deviceAccountId != null)
|
|
RemoveMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
}
|
|
#endregion
|
|
|
|
#region User Scope
|
|
private bool DeviceUserContainAttachment(DiscoDataContext Database, string UserId, out List<Tuple<string, string>> Devices)
|
|
{
|
|
var result = Database.Users
|
|
.Where(u => u.UserId == UserId)
|
|
.Select(u => new Tuple<bool, IEnumerable<Tuple<string, string>>>(
|
|
u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId),
|
|
u.DeviceUserAssignments
|
|
.Where(dua => !dua.UnassignedDate.HasValue && dua.Device.DeviceDomainId != null)
|
|
.Select(dua => new Tuple<string, string>(dua.Device.DeviceDomainId, dua.Device.SerialNumber)))
|
|
).FirstOrDefault();
|
|
|
|
if (result == null)
|
|
{
|
|
Devices = null;
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
Devices = result.Item2
|
|
.Where(d => ActiveDirectory.IsValidDomainAccountId(d.Item1))
|
|
.Select(d => Tuple.Create(d.Item1 + "$", d.Item2))
|
|
.ToList();
|
|
return result.Item1;
|
|
}
|
|
}
|
|
|
|
private void ProcessUserRepositoryEvent(RepositoryMonitorEvent e)
|
|
{
|
|
var attachment = (UserAttachment)e.Entity;
|
|
|
|
List<Tuple<string, string>> devices;
|
|
if (DeviceUserContainAttachment(e.Database, attachment.UserId, out devices))
|
|
{
|
|
if (devices != null)
|
|
devices.ForEach(d => AddMember(d.Item2, (database) => new string[] { d.Item1 }));
|
|
}
|
|
else
|
|
{
|
|
if (devices != null)
|
|
devices.ForEach(d => RemoveMember(d.Item2, (database) => new string[] { d.Item1 }));
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
private void ProcessDeviceRenameRepositoryEvent(RepositoryMonitorEvent Event)
|
|
{
|
|
var device = (Device)Event.Entity;
|
|
var deviceSerialNumber = device.SerialNumber;
|
|
var deviceAccountId = device.DeviceDomainId;
|
|
var deviceAccountIdValid = ActiveDirectory.IsValidDomainAccountId(deviceAccountId);
|
|
var devicePreviousAccountId = Event.GetPreviousPropertyValue<string>("DeviceDomainId");
|
|
var devicePreviousAccountIdValid = ActiveDirectory.IsValidDomainAccountId(devicePreviousAccountId);
|
|
|
|
if (deviceAccountIdValid || devicePreviousAccountIdValid)
|
|
{
|
|
Event.ExecuteAfterCommit(e =>
|
|
{
|
|
switch (DocumentTemplateScope)
|
|
{
|
|
case DocumentTemplate.DocumentTemplateScopes.Device:
|
|
if (DeviceContainsAttachment(e.Database, device.SerialNumber, out deviceAccountId))
|
|
{
|
|
if (deviceAccountIdValid)
|
|
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId });
|
|
if (devicePreviousAccountIdValid)
|
|
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
|
}
|
|
break;
|
|
case DocumentTemplate.DocumentTemplateScopes.Job:
|
|
var jobsHaveTemplate = e.Database.Jobs
|
|
.Where(j => !j.ClosedDate.HasValue && j.DeviceSerialNumber == deviceSerialNumber)
|
|
.Any(j => j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
|
|
|
if (jobsHaveTemplate)
|
|
{
|
|
if (deviceAccountIdValid)
|
|
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
|
if (devicePreviousAccountIdValid)
|
|
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
|
}
|
|
break;
|
|
case DocumentTemplate.DocumentTemplateScopes.User:
|
|
var userHasTemplate = e.Database.Devices
|
|
.Where(d => d.SerialNumber == deviceSerialNumber)
|
|
.Select(d => d.AssignedUser)
|
|
.Any(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
|
|
|
if (userHasTemplate)
|
|
{
|
|
if (deviceAccountIdValid)
|
|
AddMember(device.SerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
|
if (devicePreviousAccountIdValid)
|
|
RemoveMember(device.SerialNumber, (database) => new string[] { devicePreviousAccountId + "$" });
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private void ProcessJobCloseRepositoryEvent(RepositoryMonitorEvent e)
|
|
{
|
|
var job = (Job)e.Entity;
|
|
|
|
if (job.DeviceSerialNumber != null)
|
|
{
|
|
var jobId = job.Id;
|
|
|
|
var relevantJob = e.Database.Jobs
|
|
.Where(j => j.Id == jobId && j.JobAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
|
.Any();
|
|
|
|
if (relevantJob)
|
|
{
|
|
string deviceAccountId;
|
|
string deviceSerialNumber;
|
|
if (JobsContainAttachment(e.Database, jobId, out deviceAccountId, out deviceSerialNumber))
|
|
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
else
|
|
RemoveMember(deviceSerialNumber, (database) => new string[] { deviceAccountId });
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProcessDeviceAssignmentRepositoryEvent(RepositoryMonitorEvent Event)
|
|
{
|
|
var device = (Device)Event.Entity;
|
|
var deviceSerialNumber = device.SerialNumber;
|
|
var deviceAccountId = device.DeviceDomainId;
|
|
|
|
if (ActiveDirectory.IsValidDomainAccountId(deviceAccountId))
|
|
{
|
|
var deviceCurrentAssignedUserId = device.AssignedUserId;
|
|
var devicePreviousAssignedUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
|
|
|
Event.ExecuteAfterCommit(e =>
|
|
{
|
|
bool previousUserHasTemplate = false;
|
|
bool currentUserHasTemplate = false;
|
|
|
|
if (devicePreviousAssignedUserId != null)
|
|
previousUserHasTemplate = e.Database.Users
|
|
.Where(u => u.UserId == devicePreviousAssignedUserId && u.UserAttachments.Any(ua => ua.DocumentTemplateId == this.DocumentTemplateId))
|
|
.Any();
|
|
|
|
if (deviceCurrentAssignedUserId != null)
|
|
currentUserHasTemplate = e.Database.Users
|
|
.Where(u => u.UserId == deviceCurrentAssignedUserId && u.UserAttachments.Any(ua => ua.DocumentTemplateId == this.DocumentTemplateId))
|
|
.Any();
|
|
|
|
if (!previousUserHasTemplate && currentUserHasTemplate)
|
|
AddMember(deviceSerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
|
else if (previousUserHasTemplate && !currentUserHasTemplate)
|
|
RemoveMember(deviceSerialNumber, (database) => new string[] { deviceAccountId + "$" });
|
|
});
|
|
}
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
if (repositorySubscription != null)
|
|
repositorySubscription.Dispose();
|
|
|
|
if (deviceRenameRepositorySubscription != null)
|
|
deviceRenameRepositorySubscription.Dispose();
|
|
|
|
if (jobCloseRepositorySubscription != null)
|
|
jobCloseRepositorySubscription.Dispose();
|
|
|
|
if (deviceAssignmentRepositorySubscription != null)
|
|
deviceAssignmentRepositorySubscription.Dispose();
|
|
}
|
|
}
|
|
}
|