Feature #49: Active Directory Managed Groups
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.
This commit is contained in:
@@ -501,9 +501,12 @@ namespace Disco.BI.DeviceBI
|
||||
}
|
||||
else
|
||||
{
|
||||
var computerId = Disco.Services.UserExtensions.SplitUserId(RepoDevice.DeviceDomainId);
|
||||
response.DeviceDomainName = computerId.Item1;
|
||||
response.DeviceComputerName = computerId.Item2;
|
||||
string accountUsername;
|
||||
ADDomain accountDomain;
|
||||
ActiveDirectory.ParseDomainAccountId(RepoDevice.DeviceDomainId, out accountUsername, out accountDomain);
|
||||
|
||||
response.DeviceDomainName = accountDomain == null ? null : accountDomain.NetBiosName;
|
||||
response.DeviceComputerName = accountUsername;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -527,16 +530,17 @@ namespace Disco.BI.DeviceBI
|
||||
domain = ActiveDirectory.Context.GetDomainFromDistinguishedName(RepoDevice.DeviceProfile.OrganisationalUnit);
|
||||
|
||||
var calculatedComputerName = RepoDevice.ComputerNameRender(Database, domain);
|
||||
var computerNameSplit = Disco.Services.UserExtensions.SplitUserId(calculatedComputerName);
|
||||
string calculatedAccountUsername;
|
||||
ActiveDirectory.ParseDomainAccountId(calculatedComputerName, out calculatedAccountUsername);
|
||||
|
||||
if (!Request.DeviceComputerName.Equals(computerNameSplit.Item2, StringComparison.OrdinalIgnoreCase))
|
||||
if (!Request.DeviceComputerName.Equals(calculatedAccountUsername, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
EnrolmentLog.LogSessionProgress(sessionId, 50, string.Format("Renaming Device: {0} -> {1}", Request.DeviceComputerName, calculatedComputerName));
|
||||
EnrolmentLog.LogSessionTaskRenamingDevice(sessionId, Request.DeviceComputerName, calculatedComputerName);
|
||||
|
||||
RepoDevice.DeviceDomainId = calculatedComputerName;
|
||||
response.DeviceDomainName = computerNameSplit.Item1;
|
||||
response.DeviceComputerName = computerNameSplit.Item2;
|
||||
response.DeviceDomainName = domain.NetBiosName;
|
||||
response.DeviceComputerName = calculatedAccountUsername;
|
||||
|
||||
// Create New Account
|
||||
string offlineProvisionDiagnosicInfo;
|
||||
|
||||
@@ -66,14 +66,10 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
}
|
||||
public DocumentUniqueIdentifier(string TemplateTypeId, string DataId, string CreatorId, DateTime TimeStamp, int? Page = null, string Tag = null)
|
||||
{
|
||||
var creatorId = (string.IsNullOrEmpty(CreatorId) || CreatorId.IndexOf('\\') > -1)
|
||||
? CreatorId
|
||||
: string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, CreatorId);
|
||||
|
||||
this.Tag = Tag;
|
||||
this.TemplateTypeId = TemplateTypeId;
|
||||
this.DataId = DataId;
|
||||
this.CreatorId = creatorId;
|
||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(CreatorId);
|
||||
this.TimeStamp = TimeStamp;
|
||||
this.Page = Page ?? 0;
|
||||
}
|
||||
@@ -98,11 +94,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
}
|
||||
if (s.Length >= 5)
|
||||
{
|
||||
var creatorId = s[4];
|
||||
if (!string.IsNullOrWhiteSpace(creatorId) && creatorId.IndexOf('\\') < 0)
|
||||
creatorId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, creatorId);
|
||||
|
||||
this.CreatorId = creatorId;
|
||||
this.CreatorId = ActiveDirectory.ParseDomainAccountId(s[4]);
|
||||
}
|
||||
if (s.Length >= 6)
|
||||
{
|
||||
@@ -189,13 +181,7 @@ namespace Disco.BI.DocumentTemplateBI
|
||||
}
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
|
||||
// Patch for existing documents (before DBv13 - Multi-Domain Support)
|
||||
// Add default domain to User Ids
|
||||
if (this.DataId.IndexOf('\\') < 0)
|
||||
this.DataId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, this.DataId);
|
||||
|
||||
User u = Database.Users.Find(this.DataId);
|
||||
User u = Database.Users.Find(ActiveDirectory.ParseDomainAccountId(this.DataId));
|
||||
if (u != null)
|
||||
{
|
||||
this._data = u;
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
||||
{
|
||||
public static class DocumentTemplateManagedGroups
|
||||
{
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceScopeRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> JobScopeRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> UserScopeRepositoryEvents;
|
||||
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceRenameRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> JobCloseRepositoryEvents;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceAssignmentRepositoryEvents;
|
||||
|
||||
static DocumentTemplateManagedGroups()
|
||||
{
|
||||
DeviceScopeRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(DeviceAttachment) &&
|
||||
((DeviceAttachment)e.Entity).DocumentTemplateId != null && (
|
||||
(e.EventType == RepositoryMonitorEventType.Added) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
)
|
||||
));
|
||||
JobScopeRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(JobAttachment) && (
|
||||
(e.EventType == RepositoryMonitorEventType.Added) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
)
|
||||
));
|
||||
UserScopeRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(UserAttachment) && (
|
||||
(e.EventType == RepositoryMonitorEventType.Added) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
)
|
||||
));
|
||||
|
||||
DeviceRenameRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("DeviceDomainId")
|
||||
));
|
||||
JobCloseRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(Job) &&
|
||||
(((Job)e.Entity).DeviceSerialNumber != null || ((Job)e.Entity).UserId != null) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("ClosedDate")
|
||||
));
|
||||
DeviceAssignmentRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) &&
|
||||
e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
e.ModifiedProperties.Contains("AssignedUserId")
|
||||
));
|
||||
}
|
||||
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
Database.DocumentTemplates
|
||||
.Where(dp => dp.DevicesLinkedGroup != null || dp.UsersLinkedGroup != null)
|
||||
.ToList()
|
||||
.ForEach(dp =>
|
||||
{
|
||||
DocumentTemplateDevicesManagedGroup.Initialize(dp);
|
||||
DocumentTemplateUsersManagedGroup.Initialize(dp);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.BI.DocumentTemplateBI.ManagedGroups
|
||||
{
|
||||
public class DocumentTemplateUsersManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DocumentTemplate_{0}_Users";
|
||||
private const string UserDescriptionFormat = "Users with a {0} attachment will be added to this Active Directory group.";
|
||||
private const string DescriptionFormat = "{0}s with a {1} attachment will have any associated users added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Related Users Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Document Template Users]";
|
||||
|
||||
private IDisposable repositorySubscription;
|
||||
private IDisposable jobCloseRepositorySubscription;
|
||||
private IDisposable deviceAssignmentRepositorySubscription;
|
||||
private string DocumentTemplateId;
|
||||
private string DocumentTemplateDescription;
|
||||
private string DocumentTemplateScope;
|
||||
|
||||
public override string Description { get { return GetDescription(DocumentTemplateScope, DocumentTemplateDescription); } }
|
||||
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
||||
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DocumentTemplateDescription); } }
|
||||
public override bool IncludeFilterBeginDate { get { return true; } }
|
||||
|
||||
private DocumentTemplateUsersManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DocumentTemplate DocumentTemplate)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DocumentTemplateId = DocumentTemplate.Id;
|
||||
this.DocumentTemplateDescription = DocumentTemplate.Description;
|
||||
this.DocumentTemplateScope = DocumentTemplate.Scope;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// Subscribe to changes
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
// Observe Device Attachments
|
||||
repositorySubscription = DocumentTemplateManagedGroups.DeviceScopeRepositoryEvents.Value
|
||||
.Where(e => ((DeviceAttachment)e.Entity).DocumentTemplateId == DocumentTemplateId)
|
||||
.Subscribe(ProcessDeviceRepositoryEvent);
|
||||
// Observe Device Assignments
|
||||
deviceAssignmentRepositorySubscription = DocumentTemplateManagedGroups.DeviceAssignmentRepositoryEvents.Value
|
||||
.Subscribe(ProcessDeviceAssignmentRepositoryEvent);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetKey(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return string.Format(KeyFormat, DocumentTemplate.Id);
|
||||
}
|
||||
private static string GetDescription(string DocumentTemplateScope, string DocumentTemplateDescription)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
return string.Format(DescriptionFormat, DocumentTemplateScope, DocumentTemplateDescription);
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return string.Format(UserDescriptionFormat, DocumentTemplateDescription);
|
||||
default:
|
||||
throw new ArgumentException("Unknown Document Template Scope", "Scope");
|
||||
}
|
||||
}
|
||||
public static string GetDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return GetDescription(DocumentTemplate.Scope, DocumentTemplate.Description);
|
||||
}
|
||||
public static string GetCategoryDescription(DocumentTemplate DocumentTemplate)
|
||||
{
|
||||
return CategoryDescriptionFormat;
|
||||
}
|
||||
|
||||
public static bool TryGetManagedGroup(DocumentTemplate DocumentTemplate, out DocumentTemplateUsersManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DocumentTemplate);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DocumentTemplateUsersManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DocumentTemplateUsersManagedGroup Initialize(DocumentTemplate Template)
|
||||
{
|
||||
var key = GetKey(Template);
|
||||
|
||||
if (!string.IsNullOrEmpty(Template.UsersLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(Template.UsersLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DocumentTemplateUsersManagedGroup(
|
||||
key,
|
||||
config,
|
||||
Template);
|
||||
|
||||
// Add to AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.AddOrUpdate(group);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from AD Context
|
||||
ActiveDirectory.Context.ManagedGroups.Remove(key);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
switch (DocumentTemplateScope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
return Database.Devices
|
||||
.Where(d => d.AssignedUserId != null && d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(d => d.AssignedUserId);
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
return Database.Jobs
|
||||
.Where(j => !j.ClosedDate.HasValue && j.UserId != null && j.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(j => j.UserId)
|
||||
.Distinct();
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
return Database.Users
|
||||
.Where(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Select(u => u.UserId);
|
||||
default:
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
#region Device Scope
|
||||
private bool DeviceContainsAttachment(DiscoDataContext Database, string DeviceSerialNumber, out string UserId)
|
||||
{
|
||||
var result = Database.Devices
|
||||
.Where(d => d.SerialNumber == DeviceSerialNumber && d.AssignedUser != null)
|
||||
.Select(d => new Tuple<string, bool>(d.AssignedUserId, d.DeviceAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
UserId = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserId = result.Item1;
|
||||
return result.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (DeviceAttachment)e.Entity;
|
||||
|
||||
string userId;
|
||||
if (DeviceContainsAttachment(e.Database, attachment.DeviceSerialNumber, out userId))
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
else if (userId != null)
|
||||
RemoveMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Job Scope
|
||||
private bool JobsContainAttachment(DiscoDataContext Database, int JobId, out string UserId)
|
||||
{
|
||||
var result = Database.Jobs
|
||||
.Where(j => j.Id == JobId && j.UserId != null)
|
||||
.Select(j => new Tuple<string, bool>(
|
||||
j.UserId,
|
||||
j.User.Jobs.Where(uj => !uj.ClosedDate.HasValue).Any(uj => uj.JobAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId)))
|
||||
).FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
UserId = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserId = result.Item1;
|
||||
return result.Item2;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessJobRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (JobAttachment)e.Entity;
|
||||
|
||||
string userId;
|
||||
if (JobsContainAttachment(e.Database, attachment.JobId, out userId))
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
else if (userId != null)
|
||||
RemoveMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User Scope
|
||||
private bool UserContainAttachment(DiscoDataContext Database, string UserId)
|
||||
{
|
||||
var result = Database.Users
|
||||
.Where(u => u.UserId == UserId)
|
||||
.Any(u => u.UserAttachments.Any(a => a.DocumentTemplateId == this.DocumentTemplateId));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ProcessUserRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var attachment = (UserAttachment)e.Entity;
|
||||
var userId = attachment.UserId;
|
||||
|
||||
if (UserContainAttachment(e.Database, userId))
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
else
|
||||
RemoveMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void ProcessJobCloseRepositoryEvent(RepositoryMonitorEvent e)
|
||||
{
|
||||
var job = (Job)e.Entity;
|
||||
|
||||
if (job.UserId != null)
|
||||
{
|
||||
var jobId = job.Id;
|
||||
|
||||
var relevantJob = e.Database.Jobs
|
||||
.Where(j => j.Id == jobId && j.JobAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (relevantJob)
|
||||
{
|
||||
string userId;
|
||||
if (JobsContainAttachment(e.Database, jobId, out userId))
|
||||
AddMember(userId, (database) => new string[] { userId });
|
||||
else
|
||||
RemoveMember(userId, (database) => new string[] { userId });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessDeviceAssignmentRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
var deviceSerialNumber = device.SerialNumber;
|
||||
|
||||
var relevantDevice = Event.Database.Devices
|
||||
.Where(d => d.SerialNumber == deviceSerialNumber && d.DeviceAttachments.Any(ja => ja.DocumentTemplateId == this.DocumentTemplateId))
|
||||
.Any();
|
||||
|
||||
if (relevantDevice)
|
||||
{
|
||||
var deviceCurrentAssignedUserId = device.AssignedUserId;
|
||||
var devicePreviousAssignedUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
if (devicePreviousAssignedUserId != null)
|
||||
RemoveMember(devicePreviousAssignedUserId, (database) => new string[] { devicePreviousAssignedUserId });
|
||||
|
||||
if (deviceCurrentAssignedUserId != null)
|
||||
AddMember(deviceCurrentAssignedUserId, (database) => new string[] { deviceCurrentAssignedUserId });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositorySubscription != null)
|
||||
repositorySubscription.Dispose();
|
||||
|
||||
if (jobCloseRepositorySubscription != null)
|
||||
jobCloseRepositorySubscription.Dispose();
|
||||
|
||||
if (deviceAssignmentRepositorySubscription != null)
|
||||
deviceAssignmentRepositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using Disco.BI.Extensions;
|
||||
using System.Diagnostics;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions
|
||||
{
|
||||
@@ -20,7 +17,7 @@ namespace Disco.BI.Expressions
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// Run in Background 1 Second after Scheduled (on App Startup)
|
||||
// Run in Background 5 Second after Scheduled (on App Startup)
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(new DateTimeOffset(DateTime.Now).AddSeconds(5));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
@@ -37,8 +34,6 @@ namespace Disco.BI.Expressions
|
||||
documentTemplate.FilterExpressionFromCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
var adMachineAccount = Device.ActiveDirectoryAccount(PropertyName);
|
||||
if (adMachineAccount != null)
|
||||
return adMachineAccount.GetPropertyValue(PropertyName, Index);
|
||||
return adMachineAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
@@ -11,7 +11,7 @@ namespace Disco.BI.Expressions.Extensions
|
||||
{
|
||||
var adUserAccount = User.ActiveDirectoryAccount(PropertyName);
|
||||
if (adUserAccount != null)
|
||||
return adUserAccount.GetPropertyValue(PropertyName, Index);
|
||||
return adUserAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Disco.BI.Extensions
|
||||
|
||||
public static bool UpdateLastNetworkLogonDate(this Device Device)
|
||||
{
|
||||
return Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDate(Device);
|
||||
return Disco.Services.Interop.ActiveDirectory.ADNetworkLogonDatesUpdateTask.UpdateLastNetworkLogonDate(Device);
|
||||
}
|
||||
|
||||
public static DeviceAttachment CreateAttachment(this Device Device, DiscoDataContext Database, User CreatorUser, string Filename, string MimeType, string Comments, Stream Content, DocumentTemplate DocumentTemplate = null, byte[] PdfThumbnail = null)
|
||||
@@ -142,10 +142,7 @@ namespace Disco.BI.Extensions
|
||||
Database.Devices.Add(d2);
|
||||
if (!string.IsNullOrEmpty(d.AssignedUserId))
|
||||
{
|
||||
if (!d.AssignedUserId.Contains('\\'))
|
||||
d.AssignedUserId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, d.AssignedUserId);
|
||||
|
||||
User u = UserService.GetUser(d.AssignedUserId, Database, true);
|
||||
User u = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(d.AssignedUserId), Database, true);
|
||||
d2.AssignDevice(Database, u);
|
||||
}
|
||||
|
||||
|
||||
@@ -66,10 +66,8 @@ namespace Disco.BI.Interop.Pdf
|
||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
||||
{
|
||||
string dataObjectId = DataObjectsIds[idIndex];
|
||||
if (!dataObjectId.Contains('\\'))
|
||||
dataObjectId = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + dataObjectId;
|
||||
|
||||
DataObjects[idIndex] = UserService.GetUser(dataObjectId, Database, true);
|
||||
DataObjects[idIndex] = UserService.GetUser(ActiveDirectory.ParseDomainAccountId(dataObjectId), Database, true);
|
||||
if (DataObjects[idIndex] == null)
|
||||
throw new Exception(string.Format("Unknown Username specified: {0}", dataObjectId));
|
||||
}
|
||||
|
||||
@@ -98,6 +98,9 @@
|
||||
<Compile Include="BI\DeviceBI\Migration\LogMacAddressImporting.cs" />
|
||||
<Compile Include="BI\DisposableImageCollection.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\DocumentTemplateQRCodeLocationCache.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateUsersManagedGroup.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateDevicesManagedGroup.cs" />
|
||||
<Compile Include="BI\DocumentTemplateBI\ManagedGroups\DocumentTemplateManagedGroups.cs" />
|
||||
<Compile Include="BI\Expressions\EvaluateExpressionParseException.cs" />
|
||||
<Compile Include="BI\Expressions\ExpressionCachePreloadTask.cs" />
|
||||
<Compile Include="BI\Expressions\Extensions\DataExt.cs" />
|
||||
@@ -204,7 +207,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_StartDate="2011/7/1" BuildVersion_BuildAction="Both" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_BuildAction="Both" BuildVersion_StartDate="2011/7/1" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -139,9 +139,9 @@
|
||||
<Compile Include="Migrations\201404080227546_DBv13.Designer.cs">
|
||||
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\201406090652547_DBv14.cs" />
|
||||
<Compile Include="Migrations\201406090652547_DBv14.Designer.cs">
|
||||
<DependentUpon>201406090652547_DBv14.cs</DependentUpon>
|
||||
<Compile Include="Migrations\201406160912525_DBv14.cs" />
|
||||
<Compile Include="Migrations\201406160912525_DBv14.Designer.cs">
|
||||
<DependentUpon>201406160912525_DBv14.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Migrations\Configuration.cs" />
|
||||
<Compile Include="Migrations\DiscoDataMigrator.cs" />
|
||||
@@ -197,8 +197,8 @@
|
||||
<EmbeddedResource Include="Migrations\201404080227546_DBv13.resx">
|
||||
<DependentUpon>201404080227546_DBv13.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Migrations\201406090652547_DBv14.resx">
|
||||
<DependentUpon>201406090652547_DBv14.cs</DependentUpon>
|
||||
<EmbeddedResource Include="Migrations\201406160912525_DBv14.resx">
|
||||
<DependentUpon>201406160912525_DBv14.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -11,7 +11,7 @@ namespace Disco.Data.Migrations
|
||||
|
||||
string IMigrationMetadata.Id
|
||||
{
|
||||
get { return "201406090652547_DBv14"; }
|
||||
get { return "201406160912525_DBv14"; }
|
||||
}
|
||||
|
||||
string IMigrationMetadata.Source
|
||||
+14
@@ -39,9 +39,17 @@ namespace Disco.Data.Migrations
|
||||
Description = c.String(maxLength: 500),
|
||||
Icon = c.String(nullable: false, maxLength: 25),
|
||||
IconColour = c.String(nullable: false, maxLength: 10),
|
||||
UsersLinkedGroup = c.String(),
|
||||
UserDevicesLinkedGroup = c.String(),
|
||||
})
|
||||
.PrimaryKey(t => t.Id);
|
||||
|
||||
AddColumn("dbo.DocumentTemplates", "DevicesLinkedGroup", c => c.String());
|
||||
AddColumn("dbo.DocumentTemplates", "UsersLinkedGroup", c => c.String());
|
||||
AddColumn("dbo.DeviceProfiles", "DevicesLinkedGroup", c => c.String());
|
||||
AddColumn("dbo.DeviceProfiles", "AssignedUsersLinkedGroup", c => c.String());
|
||||
AddColumn("dbo.DeviceBatches", "DevicesLinkedGroup", c => c.String());
|
||||
AddColumn("dbo.DeviceBatches", "AssignedUsersLinkedGroup", c => c.String());
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
@@ -54,6 +62,12 @@ namespace Disco.Data.Migrations
|
||||
DropForeignKey("dbo.UserFlagAssignments", "AddedUserId", "dbo.Users");
|
||||
DropForeignKey("dbo.UserFlagAssignments", "UserId", "dbo.Users");
|
||||
DropForeignKey("dbo.UserFlagAssignments", "UserFlagId", "dbo.UserFlags");
|
||||
DropColumn("dbo.DeviceBatches", "AssignedUsersLinkedGroup");
|
||||
DropColumn("dbo.DeviceBatches", "DevicesLinkedGroup");
|
||||
DropColumn("dbo.DeviceProfiles", "AssignedUsersLinkedGroup");
|
||||
DropColumn("dbo.DeviceProfiles", "DevicesLinkedGroup");
|
||||
DropColumn("dbo.DocumentTemplates", "UsersLinkedGroup");
|
||||
DropColumn("dbo.DocumentTemplates", "DevicesLinkedGroup");
|
||||
DropTable("dbo.UserFlags");
|
||||
DropTable("dbo.UserFlagAssignments");
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -111,6 +111,7 @@
|
||||
<Compile Include="Services\Devices\Importing\IDeviceImportRecord.cs" />
|
||||
<Compile Include="Services\Devices\Importing\IDeviceImportContext.cs" />
|
||||
<Compile Include="Services\Devices\Importing\IDeviceImportField.cs" />
|
||||
<Compile Include="Services\Interop\ActiveDirectory\ADManagedGroupConfiguration.cs" />
|
||||
<Compile Include="Services\Jobs\JobLists\JobLocationReference.cs" />
|
||||
<Compile Include="Services\Jobs\JobLists\JobTableItemModel.cs" />
|
||||
<Compile Include="Services\Jobs\JobLists\JobTableModel.cs" />
|
||||
@@ -181,7 +182,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace Disco.Models.Repository
|
||||
[DataType(DataType.MultilineText)]
|
||||
public string Comments { get; set; }
|
||||
|
||||
public string DevicesLinkedGroup { get; set; }
|
||||
public string AssignedUsersLinkedGroup { get; set; }
|
||||
|
||||
[ForeignKey("DefaultDeviceModelId")]
|
||||
public virtual DeviceModel DefaultDeviceModel { get; set; }
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ namespace Disco.Models.Repository
|
||||
|
||||
public bool AllowUntrustedReimageJobEnrolment { get; set; }
|
||||
|
||||
public string DevicesLinkedGroup { get; set; }
|
||||
public string AssignedUsersLinkedGroup { get; set; }
|
||||
|
||||
public virtual IList<Device> Devices { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -18,13 +18,16 @@ namespace Disco.Models.Repository
|
||||
public string Description { get; set; }
|
||||
[Required, StringLength(6)]
|
||||
public string Scope { get; set; }
|
||||
[StringLength(250)]
|
||||
[StringLength(250), DataType(DataType.MultilineText)]
|
||||
public string FilterExpression { get; set; }
|
||||
|
||||
// Feature Request 2012-05-10 by G#: https://disco.uservoice.com/forums/159707-feedback/suggestions/2811092-document-template-option-flatten-form-on-generate
|
||||
public bool FlattenForm { get; set; }
|
||||
// End Feature Request
|
||||
|
||||
public string DevicesLinkedGroup { get; set; }
|
||||
public string UsersLinkedGroup { get; set; }
|
||||
|
||||
[InverseProperty("DocumentTemplates")]
|
||||
public virtual IList<JobSubType> JobSubTypes { get; set; }
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ namespace Disco.Models.Repository
|
||||
[Required, StringLength(10)]
|
||||
public string IconColour { get; set; }
|
||||
|
||||
public string UsersLinkedGroup { get; set; }
|
||||
public string UserDevicesLinkedGroup { get; set; }
|
||||
|
||||
public virtual IList<UserFlagAssignment> UserFlagAssignments { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Disco.Models.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADManagedGroupConfiguration
|
||||
{
|
||||
public string GroupId { get; set; }
|
||||
public DateTime? FilterBeginDate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,7 @@ namespace Disco.Services.Authorization.Roles
|
||||
|
||||
private static IEnumerable<string> GenerateAdministratorSubjectIds(DiscoDataContext Database)
|
||||
{
|
||||
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
|
||||
var configuredSubjectIds = Database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Contains(@"\") ? s : string.Format(@"{0}\{1}", domainNetBiosName, s));
|
||||
var configuredSubjectIds = Database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => ActiveDirectory.ParseDomainAccountId(s));
|
||||
|
||||
return RequiredAdministratorSubjectIds
|
||||
.Concat(configuredSubjectIds)
|
||||
@@ -62,8 +61,7 @@ namespace Disco.Services.Authorization.Roles
|
||||
{
|
||||
get
|
||||
{
|
||||
var domainNetBiosName = ActiveDirectory.Context.PrimaryDomain.NetBiosName;
|
||||
return _RequiredAdministratorSubjectIds.Select(s => string.Format(@"{0}\{1}", domainNetBiosName, s));
|
||||
return _RequiredAdministratorSubjectIds.Select(s => ActiveDirectory.ParseDomainAccountId(s));
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> AdministratorSubjectIds
|
||||
|
||||
@@ -55,7 +55,7 @@ namespace Disco.Services.Devices.Exporting
|
||||
TaskStatus.ProgressMultiplier = 20 / 100;
|
||||
TaskStatus.ProgressOffset = 40;
|
||||
|
||||
Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.UpdateLastNetworkLogonDates(Database, TaskStatus);
|
||||
Interop.ActiveDirectory.ADNetworkLogonDatesUpdateTask.UpdateLastNetworkLogonDates(Database, TaskStatus);
|
||||
Database.SaveChanges();
|
||||
|
||||
TaskStatus.IgnoreCurrentProcessChanges = false;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Devices.Importing;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -34,8 +35,7 @@ namespace Disco.Services.Devices.Importing.Fields
|
||||
{
|
||||
parsedValue = Value.Trim();
|
||||
|
||||
if (!parsedValue.Contains('\\'))
|
||||
parsedValue = string.Format(@"{0}\{1}", Interop.ActiveDirectory.ActiveDirectory.Context.PrimaryDomain.NetBiosName, parsedValue);
|
||||
parsedValue = ActiveDirectory.ParseDomainAccountId(parsedValue);
|
||||
|
||||
friendlyValue = parsedValue;
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
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 DeviceBatchAssignedUsersManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DeviceBatch_{0}_AssignedUsers";
|
||||
private const string DescriptionFormat = "Devices within the {0} Batch will have their assigned users added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Assigned Users Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Device Batch Assigned Users]";
|
||||
|
||||
private static Lazy<IObservable<RepositoryMonitorEvent>> RepositoryEvents;
|
||||
|
||||
private IDisposable repositorySubscription;
|
||||
private int DeviceBatchId;
|
||||
private string DeviceBatchName;
|
||||
|
||||
public override string Description { get { return string.Format(DescriptionFormat, DeviceBatchName); } }
|
||||
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
||||
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DeviceBatchName); } }
|
||||
public override bool IncludeFilterBeginDate { get { return false; } }
|
||||
|
||||
static DeviceBatchAssignedUsersManagedGroup()
|
||||
{
|
||||
RepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) && (
|
||||
(e.EventType == RepositoryMonitorEventType.Added &&
|
||||
((Device)e.Entity).AssignedUserId != null) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
(e.ModifiedProperties.Contains("DeviceBatchId") || e.ModifiedProperties.Contains("AssignedUserId"))) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted &&
|
||||
((Device)e.Entity).AssignedUserId != null))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private DeviceBatchAssignedUsersManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DeviceBatch DeviceBatch)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DeviceBatchId = DeviceBatch.Id;
|
||||
this.DeviceBatchName = DeviceBatch.Name;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// Subscribe to changes
|
||||
repositorySubscription = RepositoryEvents.Value
|
||||
.Where(e =>
|
||||
(((Device)e.Entity).DeviceBatchId == DeviceBatchId) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.GetPreviousPropertyValue<int>("DeviceBatchId") == DeviceBatchId))
|
||||
.Subscribe(ProcessRepositoryEvent);
|
||||
}
|
||||
|
||||
public static string GetKey(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return string.Format(KeyFormat, DeviceBatch.Id);
|
||||
}
|
||||
public static string GetDescription(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return string.Format(DescriptionFormat, DeviceBatch.Name);
|
||||
}
|
||||
public static string GetCategoryDescription(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return CategoryDescriptionFormat;
|
||||
}
|
||||
|
||||
public static bool TryGetManagedGroup(DeviceBatch DeviceBatch, out DeviceBatchAssignedUsersManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DeviceBatch);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DeviceBatchAssignedUsersManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DeviceBatchAssignedUsersManagedGroup Initialize(DeviceBatch DeviceBatch)
|
||||
{
|
||||
if (DeviceBatch.Id > 0)
|
||||
{
|
||||
var key = GetKey(DeviceBatch);
|
||||
|
||||
if (!string.IsNullOrEmpty(DeviceBatch.AssignedUsersLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(DeviceBatch.AssignedUsersLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DeviceBatchAssignedUsersManagedGroup(
|
||||
key,
|
||||
config,
|
||||
DeviceBatch);
|
||||
|
||||
// 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)
|
||||
{
|
||||
return Database.Devices
|
||||
.Where(d => d.DeviceBatchId == this.DeviceBatchId)
|
||||
.Where(d => d.AssignedUserId != null)
|
||||
.Select(d => d.AssignedUserId);
|
||||
}
|
||||
|
||||
private void ProcessRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
string previousUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
switch (e.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
AddMember(device.AssignedUserId);
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (device.DeviceBatchId == this.DeviceBatchId)
|
||||
{
|
||||
if (device.AssignedUserId != null)
|
||||
AddMember(device.AssignedUserId);
|
||||
|
||||
if (e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
{
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceBatchId == this.DeviceBatchId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceBatchId == this.DeviceBatchId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
}
|
||||
break;
|
||||
case RepositoryMonitorEventType.Deleted:
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceBatchId == this.DeviceBatchId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositorySubscription != null)
|
||||
repositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
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 DeviceBatchDevicesManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DeviceBatch_{0}_Devices";
|
||||
private const string DescriptionFormat = "Devices within the {0} Batch will be added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Devices Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Device Batch Devices]";
|
||||
private static Lazy<IObservable<RepositoryMonitorEvent>> RepositoryEvents;
|
||||
|
||||
private IDisposable repositorySubscription;
|
||||
private int DeviceBatchId;
|
||||
private string DeviceBatchName;
|
||||
|
||||
public override string Description { get { return string.Format(DescriptionFormat, DeviceBatchName); } }
|
||||
public override string CategoryDescription { get { return CategoryDescriptionFormat; } }
|
||||
public override string GroupDescription { get { return string.Format(GroupDescriptionFormat, DeviceBatchName); } }
|
||||
public override bool IncludeFilterBeginDate { get { return false; } }
|
||||
|
||||
static DeviceBatchDevicesManagedGroup()
|
||||
{
|
||||
RepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
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("DeviceBatchId") || e.ModifiedProperties.Contains("DeviceDomainId"))) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
private DeviceBatchDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DeviceBatch DeviceBatch)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DeviceBatchId = DeviceBatch.Id;
|
||||
this.DeviceBatchName = DeviceBatch.Name;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
// Subscribe to changes
|
||||
repositorySubscription = RepositoryEvents.Value
|
||||
.Where(e =>
|
||||
(((Device)e.Entity).DeviceBatchId == DeviceBatchId) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified && e.GetPreviousPropertyValue<int>("DeviceBatchId") == DeviceBatchId))
|
||||
.Subscribe(ProcessRepositoryEvent);
|
||||
}
|
||||
|
||||
public static string GetKey(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return string.Format(KeyFormat, DeviceBatch.Id);
|
||||
}
|
||||
public static string GetDescription(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return string.Format(DescriptionFormat, DeviceBatch.Name);
|
||||
}
|
||||
public static string GetCategoryDescription(DeviceBatch DeviceBatch)
|
||||
{
|
||||
return CategoryDescriptionFormat;
|
||||
}
|
||||
|
||||
public static bool TryGetManagedGroup(DeviceBatch DeviceBatch, out DeviceBatchDevicesManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DeviceBatch);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DeviceBatchDevicesManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DeviceBatchDevicesManagedGroup Initialize(DeviceBatch DeviceBatch)
|
||||
{
|
||||
if (DeviceBatch.Id > 0)
|
||||
{
|
||||
var key = GetKey(DeviceBatch);
|
||||
|
||||
if (!string.IsNullOrEmpty(DeviceBatch.DevicesLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(DeviceBatch.DevicesLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DeviceBatchDevicesManagedGroup(
|
||||
key,
|
||||
config,
|
||||
DeviceBatch);
|
||||
|
||||
// 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)
|
||||
{
|
||||
return Database.Devices
|
||||
.Where(d => d.DeviceBatchId == this.DeviceBatchId)
|
||||
.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<string>("DeviceDomainId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
switch (e.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
AddMember(device.DeviceDomainId + "$");
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (device.DeviceBatchId == this.DeviceBatchId)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using Disco.Data.Repository;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Devices.ManagedGroups
|
||||
{
|
||||
public static class DeviceManagedGroups
|
||||
{
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
// Device Profiles
|
||||
Database.DeviceProfiles
|
||||
.Where(dp => dp.DevicesLinkedGroup != null || dp.AssignedUsersLinkedGroup != null)
|
||||
.ToList()
|
||||
.ForEach(dp =>
|
||||
{
|
||||
DeviceProfileDevicesManagedGroup.Initialize(dp);
|
||||
DeviceProfileAssignedUsersManagedGroup.Initialize(dp);
|
||||
});
|
||||
|
||||
// Device Batches
|
||||
Database.DeviceBatches
|
||||
.Where(db => db.DevicesLinkedGroup != null || db.AssignedUsersLinkedGroup != null)
|
||||
.ToList()
|
||||
.ForEach(db =>
|
||||
{
|
||||
DeviceBatchDevicesManagedGroup.Initialize(db);
|
||||
DeviceBatchAssignedUsersManagedGroup.Initialize(db);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
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 DeviceProfileAssignedUsersManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "DeviceProfile_{0}_AssignedUsers";
|
||||
private const string DescriptionFormat = "Devices within the {0} Profile will have their assigned users added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Assigned Users Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [Device Profile Assigned Users]";
|
||||
|
||||
private static Lazy<IObservable<RepositoryMonitorEvent>> 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 DeviceProfileAssignedUsersManagedGroup()
|
||||
{
|
||||
RepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamBeforeCommit.Where(e =>
|
||||
e.EntityType == typeof(Device) && (
|
||||
(e.EventType == RepositoryMonitorEventType.Added &&
|
||||
((Device)e.Entity).AssignedUserId != null) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Modified &&
|
||||
(e.ModifiedProperties.Contains("DeviceProfileId") || e.ModifiedProperties.Contains("AssignedUserId"))) ||
|
||||
(e.EventType == RepositoryMonitorEventType.Deleted &&
|
||||
((Device)e.Entity).AssignedUserId != null))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private DeviceProfileAssignedUsersManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DeviceProfile DeviceProfile)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DeviceProfileId = DeviceProfile.Id;
|
||||
this.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<int>("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 DeviceProfileAssignedUsersManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(DeviceProfile);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (DeviceProfileAssignedUsersManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static DeviceProfileAssignedUsersManagedGroup Initialize(DeviceProfile DeviceProfile)
|
||||
{
|
||||
if (DeviceProfile.Id > 0)
|
||||
{
|
||||
var key = GetKey(DeviceProfile);
|
||||
|
||||
if (!string.IsNullOrEmpty(DeviceProfile.AssignedUsersLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(DeviceProfile.AssignedUsersLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new DeviceProfileAssignedUsersManagedGroup(
|
||||
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<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
return Database.Devices
|
||||
.Where(d => d.DeviceProfileId == this.DeviceProfileId)
|
||||
.Where(d => d.AssignedUserId != null)
|
||||
.Select(d => d.AssignedUserId);
|
||||
}
|
||||
|
||||
private void ProcessRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var device = (Device)Event.Entity;
|
||||
string previousUserId = Event.GetPreviousPropertyValue<string>("AssignedUserId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
switch (e.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
AddMember(device.AssignedUserId);
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (device.DeviceProfileId == this.DeviceProfileId)
|
||||
{
|
||||
if (device.AssignedUserId != null)
|
||||
AddMember(device.AssignedUserId);
|
||||
|
||||
if (e.ModifiedProperties.Contains("AssignedUserId"))
|
||||
{
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceProfileId == this.DeviceProfileId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceProfileId == this.DeviceProfileId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
}
|
||||
break;
|
||||
case RepositoryMonitorEventType.Deleted:
|
||||
if (previousUserId != null)
|
||||
RemoveMember(previousUserId, (database) =>
|
||||
!database.Devices.Any(d => d.DeviceProfileId == this.DeviceProfileId && d.AssignedUserId == previousUserId)
|
||||
? new string[] { previousUserId }
|
||||
: null);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositorySubscription != null)
|
||||
repositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
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<IObservable<RepositoryMonitorEvent>> 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<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
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.EventType == RepositoryMonitorEventType.Deleted)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
private DeviceProfileDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, DeviceProfile DeviceProfile)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.DeviceProfileId = DeviceProfile.Id;
|
||||
this.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<int>("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<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
return Database.Devices
|
||||
.Where(d => d.DeviceProfileId == this.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<string>("DeviceDomainId");
|
||||
|
||||
Event.ExecuteAfterCommit(e =>
|
||||
{
|
||||
switch (e.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
AddMember(device.DeviceDomainId + "$");
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (device.DeviceProfileId == this.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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,13 @@
|
||||
<Compile Include="Devices\Importing\Fields\ModelIdImportField.cs" />
|
||||
<Compile Include="Devices\Importing\IDeviceImportCache.cs" />
|
||||
<Compile Include="Devices\DeviceUpdatesHub.cs" />
|
||||
<Compile Include="Devices\ManagedGroups\DeviceBatchAssignedUsersManagedGroup.cs" />
|
||||
<Compile Include="Devices\ManagedGroups\DeviceBatchDevicesManagedGroup.cs" />
|
||||
<Compile Include="Devices\ManagedGroups\DeviceManagedGroups.cs" />
|
||||
<Compile Include="Devices\ManagedGroups\DeviceProfileAssignedUsersManagedGroup.cs" />
|
||||
<Compile Include="Devices\ManagedGroups\DeviceProfileDevicesManagedGroup.cs" />
|
||||
<Compile Include="Extensions\DateTimeExtensions.cs" />
|
||||
<Compile Include="Extensions\EnumerableExtensions.cs" />
|
||||
<Compile Include="Extensions\RxExtensions.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Extensions\UIHelpers.cs" />
|
||||
@@ -212,6 +218,7 @@
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryContext.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryExtensions.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryGroupCache.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ActiveDirectoryManagedGroups.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDirectoryEntry.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDiscoverForestServers.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADDomain.cs" />
|
||||
@@ -219,11 +226,14 @@
|
||||
<Compile Include="Interop\ActiveDirectory\ADGroup.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADHelpers.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADMachineAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADManagedGroup.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADManagedGroupsSyncTask.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADOrganisationalUnit.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADSearchResult.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADSite.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADTaskUpdateNetworkLogonDates.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADNetworkLogonDatesUpdateTask.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\ADUserAccount.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\Description.cs" />
|
||||
<Compile Include="Interop\ActiveDirectory\IADObject.cs" />
|
||||
<Compile Include="Jobs\JobExtensions.cs" />
|
||||
<Compile Include="Jobs\JobLists\JobTableExtensions.cs" />
|
||||
@@ -300,6 +310,8 @@
|
||||
<Compile Include="Users\CacheCleanTask.cs" />
|
||||
<Compile Include="Users\UserExtensions.cs" />
|
||||
<Compile Include="Users\UserFlags\Cache.cs" />
|
||||
<Compile Include="Users\UserFlags\UserFlagUserDevicesManagedGroup.cs" />
|
||||
<Compile Include="Users\UserFlags\UserFlagUsersManagedGroup.cs" />
|
||||
<Compile Include="Users\UserFlags\UserFlagsBulkAssignTask.cs" />
|
||||
<Compile Include="Users\UserFlags\UserFlagsDeleteTask.cs" />
|
||||
<Compile Include="Users\UserFlags\UserFlagService.cs" />
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco
|
||||
{
|
||||
public static class EnumerableExtensions
|
||||
{
|
||||
|
||||
public static IEnumerable<List<TSource>> Chunk<TSource>(this IEnumerable<TSource> source, int ChunkSize)
|
||||
{
|
||||
List<TSource> buffer = new List<TSource>(ChunkSize);
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
buffer.Add(item);
|
||||
|
||||
if (buffer.Count == ChunkSize)
|
||||
{
|
||||
yield return buffer;
|
||||
buffer = new List<TSource>();
|
||||
}
|
||||
}
|
||||
|
||||
// Return any additional items
|
||||
if (buffer.Count > 0)
|
||||
yield return buffer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -193,26 +193,34 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
#endregion
|
||||
|
||||
#region Groups
|
||||
public ADGroup RetrieveADGroup(string Id)
|
||||
public ADGroup RetrieveADGroup(string Id, string[] AdditionalProperties = null)
|
||||
{
|
||||
var result = RetrieveBySamAccountName(Id, ADGroup.LdapSamAccountNameFilterTemplate, ADGroup.LoadProperties);
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? ADGroup.LoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: ADGroup.LoadProperties;
|
||||
|
||||
var result = RetrieveBySamAccountName(Id, ADGroup.LdapSamAccountNameFilterTemplate, loadProperites);
|
||||
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
return result.AsADGroup();
|
||||
return result.AsADGroup(AdditionalProperties);
|
||||
}
|
||||
public ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
|
||||
public ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName, string[] AdditionalProperties = null)
|
||||
{
|
||||
using (var groupEntry = this.RetrieveDirectoryEntry(DistinguishedName, ADGroup.LoadProperties))
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? ADGroup.LoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: ADGroup.LoadProperties;
|
||||
|
||||
using (var groupEntry = this.RetrieveDirectoryEntry(DistinguishedName, loadProperites))
|
||||
{
|
||||
if (groupEntry == null)
|
||||
return null;
|
||||
|
||||
return groupEntry.AsADGroup();
|
||||
return groupEntry.AsADGroup(AdditionalProperties);
|
||||
}
|
||||
}
|
||||
public ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
|
||||
public ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier, string[] AdditionalProperties = null)
|
||||
{
|
||||
if (SecurityIdentifier == null)
|
||||
throw new ArgumentNullException("SecurityIdentifier");
|
||||
@@ -222,12 +230,15 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
var sidBinaryString = SecurityIdentifier.ToBinaryString();
|
||||
|
||||
string ldapFilter = string.Format(ADGroup.LdapSecurityIdentifierFilterTemplate, sidBinaryString);
|
||||
string[] loadProperites = (AdditionalProperties != null && AdditionalProperties.Length > 0)
|
||||
? ADGroup.LoadProperties.Concat(AdditionalProperties).ToArray()
|
||||
: ADGroup.LoadProperties;
|
||||
|
||||
var result = this.SearchEntireDomain(ldapFilter, ADGroup.LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
var result = this.SearchEntireDomain(ldapFilter, loadProperites, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
if (result == null)
|
||||
return null;
|
||||
else
|
||||
return result.AsADGroup();
|
||||
return result.AsADGroup(AdditionalProperties);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -236,7 +247,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
private static readonly string[] ObjectLoadProperties = { "objectCategory" };
|
||||
private static readonly string[] ObjectLoadPropertiesAll = ObjectLoadProperties.Concat(ADUserAccount.LoadProperties).Concat(ADMachineAccount.LoadProperties).Concat(ADGroup.LoadProperties).Distinct().ToArray();
|
||||
|
||||
public IADObject RetrieveADObject(string Id, bool Quick)
|
||||
public IADObject RetrieveADObject(string Id, bool Quick, string[] AdditionalProperties = null)
|
||||
{
|
||||
var result = RetrieveBySamAccountName(Id, ObjectLdapSamAccountNameFilter, ObjectLoadPropertiesAll);
|
||||
|
||||
@@ -249,11 +260,11 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
switch (objectCategory)
|
||||
{
|
||||
case "cn=person":
|
||||
return result.AsADUserAccount(Quick, null);
|
||||
return result.AsADUserAccount(Quick, AdditionalProperties);
|
||||
case "cn=computer":
|
||||
return result.AsADMachineAccount(null);
|
||||
return result.AsADMachineAccount(AdditionalProperties);
|
||||
case "cn=group":
|
||||
return result.AsADGroup();
|
||||
return result.AsADGroup(AdditionalProperties);
|
||||
default:
|
||||
throw new InvalidOperationException("Unexpected objectCategory");
|
||||
}
|
||||
@@ -294,12 +305,12 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
private ADSearchResult RetrieveBySamAccountName(string Id, string LdapFilterTemplate, string[] LoadProperties)
|
||||
{
|
||||
var splitId = UserExtensions.SplitUserId(Id);
|
||||
var slashIndex = Id.IndexOf('\\');
|
||||
|
||||
if (!this.Domain.NetBiosName.Equals(splitId.Item1, StringComparison.OrdinalIgnoreCase))
|
||||
if (!this.Domain.NetBiosName.Equals(Id.Substring(0, slashIndex), StringComparison.OrdinalIgnoreCase))
|
||||
throw new ArgumentException(string.Format("The Id [{0}] is invalid for this domain [{1}]", Id, this.Domain.Name), "Id");
|
||||
|
||||
var ldapFilter = string.Format(LdapFilterTemplate, splitId.Item2);
|
||||
var ldapFilter = string.Format(LdapFilterTemplate, Id.Substring(slashIndex + 1));
|
||||
|
||||
return this.SearchEntireDomain(ldapFilter, LoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
public List<string> MemberOf { get; private set; }
|
||||
|
||||
private ADGroup(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, List<string> MemberOf)
|
||||
public Dictionary<string, object[]> LoadedProperties { get; private set; }
|
||||
|
||||
private ADGroup(ADDomain Domain, string DistinguishedName, SecurityIdentifier SecurityIdentifier, string SamAccountName, string Name, List<string> MemberOf, Dictionary<string, object[]> LoadedProperties)
|
||||
{
|
||||
this.Domain = Domain;
|
||||
this.DistinguishedName = DistinguishedName;
|
||||
@@ -34,9 +36,10 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
this.SamAccountName = SamAccountName;
|
||||
this.Name = Name;
|
||||
this.MemberOf = MemberOf;
|
||||
this.LoadedProperties = LoadedProperties;
|
||||
}
|
||||
|
||||
public static ADGroup FromSearchResult(ADSearchResult SearchResult)
|
||||
public static ADGroup FromSearchResult(ADSearchResult SearchResult, string[] AdditionalProperties)
|
||||
{
|
||||
if (SearchResult == null)
|
||||
throw new ArgumentNullException("SearchResult");
|
||||
@@ -47,10 +50,21 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
var objectSid = new SecurityIdentifier(SearchResult.Value<byte[]>("objectSid"), 0);
|
||||
var memberOf = SearchResult.Values<string>("memberOf").ToList();
|
||||
|
||||
return new ADGroup(SearchResult.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties;
|
||||
if (AdditionalProperties != null)
|
||||
additionalProperties = AdditionalProperties
|
||||
.Select(p => Tuple.Create(p, SearchResult.Values<object>(p).ToArray()))
|
||||
.ToDictionary(t => t.Item1, t => t.Item2);
|
||||
else
|
||||
{
|
||||
additionalProperties = new Dictionary<string, object[]>();
|
||||
}
|
||||
|
||||
return new ADGroup(SearchResult.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf, additionalProperties);
|
||||
}
|
||||
|
||||
public static ADGroup FromDirectoryEntry(ADDirectoryEntry DirectoryEntry)
|
||||
public static ADGroup FromDirectoryEntry(ADDirectoryEntry DirectoryEntry, string[] AdditionalProperties)
|
||||
{
|
||||
if (DirectoryEntry == null)
|
||||
throw new ArgumentNullException("DirectoryEntry");
|
||||
@@ -63,7 +77,50 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
var objectSid = new SecurityIdentifier(properties.Value<byte[]>("objectSid"), 0);
|
||||
var memberOf = properties.Values<string>("memberOf").ToList();
|
||||
|
||||
return new ADGroup(DirectoryEntry.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf);
|
||||
Dictionary<string, object[]> additionalProperties;
|
||||
if (AdditionalProperties != null)
|
||||
additionalProperties = AdditionalProperties
|
||||
.Select(p => Tuple.Create(p, properties.Values<object>(p).ToArray()))
|
||||
.ToDictionary(t => t.Item1, t => t.Item2);
|
||||
else
|
||||
{
|
||||
additionalProperties = new Dictionary<string, object[]>();
|
||||
}
|
||||
|
||||
return new ADGroup(DirectoryEntry.Domain, distinguishedName, objectSid, sAMAccountName, name, memberOf, additionalProperties);
|
||||
}
|
||||
|
||||
[Obsolete("Use generic equivalents: GetPropertyValue<T>(string PropertyName)")]
|
||||
public object GetPropertyValue(string PropertyName, int Index = 0)
|
||||
{
|
||||
return GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
}
|
||||
|
||||
public T GetPropertyValue<T>(string PropertyName)
|
||||
{
|
||||
return GetPropertyValues<T>(PropertyName).FirstOrDefault();
|
||||
}
|
||||
public IEnumerable<T> GetPropertyValues<T>(string PropertyName)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return new string[] { this.Name }.OfType<T>();
|
||||
case "samaccountname":
|
||||
return new string[] { this.SamAccountName }.OfType<T>();
|
||||
case "distinguishedname":
|
||||
return new string[] { this.DistinguishedName }.OfType<T>();
|
||||
case "objectsid":
|
||||
return new SecurityIdentifier[] { this.SecurityIdentifier }.OfType<T>();
|
||||
case "memberof":
|
||||
return this.MemberOf.OfType<T>();
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty))
|
||||
return adProperty.OfType<T>();
|
||||
else
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
||||
@@ -104,26 +104,35 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
};
|
||||
}
|
||||
|
||||
[Obsolete("Use generic equivalents: GetPropertyValue<T>(string PropertyName)")]
|
||||
public object GetPropertyValue(string PropertyName, int Index = 0)
|
||||
{
|
||||
return GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
}
|
||||
public T GetPropertyValue<T>(string PropertyName)
|
||||
{
|
||||
return GetPropertyValues<T>(PropertyName).FirstOrDefault();
|
||||
}
|
||||
public IEnumerable<T> GetPropertyValues<T>(string PropertyName)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return this.Name;
|
||||
return new string[] { this.Name }.OfType<T>();
|
||||
case "samaccountname":
|
||||
return this.SamAccountName;
|
||||
return new string[] { this.SamAccountName }.OfType<T>();
|
||||
case "distinguishedname":
|
||||
return this.DistinguishedName;
|
||||
return new string[] { this.DistinguishedName }.OfType<T>();
|
||||
case "objectsid":
|
||||
return this.SecurityIdentifier.ToString();
|
||||
return new SecurityIdentifier[] { this.SecurityIdentifier }.OfType<T>();
|
||||
case "netbootguid":
|
||||
return this.NetbootGUID;
|
||||
return new Guid[] { this.NetbootGUID }.OfType<T>();
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty))
|
||||
return adProperty.OfType<T>();
|
||||
else
|
||||
return null;
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Services.Interop.ActiveDirectory;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public abstract class ADManagedGroup : IDisposable
|
||||
{
|
||||
public string Key { get; private set; }
|
||||
public ADManagedGroupConfiguration Configuration { get; private set; }
|
||||
|
||||
internal ActiveDirectoryManagedGroups Context { get; set; }
|
||||
|
||||
public abstract string Description { get; }
|
||||
public abstract string CategoryDescription { get; }
|
||||
public abstract string GroupDescription { get; }
|
||||
public abstract bool IncludeFilterBeginDate { get; }
|
||||
|
||||
public ADManagedGroup(string Key, ADManagedGroupConfiguration Configuration)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Key))
|
||||
throw new ArgumentNullException("Key");
|
||||
if (Configuration == null)
|
||||
throw new ArgumentNullException("Configuration");
|
||||
if (!ActiveDirectory.IsValidDomainAccountId(Configuration.GroupId))
|
||||
throw new ArgumentException("Configuration.GroupId is not a valid Domain Account Id", "Configuration");
|
||||
|
||||
this.Key = Key;
|
||||
this.Configuration = Configuration;
|
||||
}
|
||||
|
||||
public abstract void Initialize();
|
||||
public abstract IEnumerable<string> DetermineMembers(DiscoDataContext Database);
|
||||
|
||||
public ADGroup GetGroup()
|
||||
{
|
||||
return ActiveDirectory.RetrieveADGroup(this.Configuration.GroupId, "member");
|
||||
}
|
||||
|
||||
protected void AddMember(string Id)
|
||||
{
|
||||
AddMember(Id, null);
|
||||
}
|
||||
protected void AddMember(string InvokingIdentifier, Func<DiscoDataContext, IEnumerable<string>> MemberResolver)
|
||||
{
|
||||
if (Context == null)
|
||||
return; // Must be added to ActiveDirectoryManagedGroups
|
||||
|
||||
var action = new ADManagedGroupScheduledAction(
|
||||
this,
|
||||
ADManagedGroupScheduledActionType.AddGroupMember,
|
||||
InvokingIdentifier,
|
||||
MemberResolver);
|
||||
|
||||
Context.ScheduleAction(action);
|
||||
}
|
||||
|
||||
protected void RemoveMember(string Id)
|
||||
{
|
||||
RemoveMember(Id, null);
|
||||
}
|
||||
protected void RemoveMember(string InvokingIdentifier, Func<DiscoDataContext, IEnumerable<string>> MemberResolver)
|
||||
{
|
||||
if (Context == null)
|
||||
return; // Must be added to ActiveDirectoryManagedGroups
|
||||
|
||||
var action = new ADManagedGroupScheduledAction(
|
||||
this,
|
||||
ADManagedGroupScheduledActionType.RemoveGroupMember,
|
||||
InvokingIdentifier,
|
||||
MemberResolver);
|
||||
|
||||
Context.ScheduleAction(action);
|
||||
}
|
||||
|
||||
public static ADManagedGroupConfiguration ConfigurationFromJson(string ConfigurationJson)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<ADManagedGroupConfiguration>(ConfigurationJson);
|
||||
}
|
||||
public static string ValidConfigurationToJson(string GroupKey, string GroupId, DateTime? FilterBeginDate)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(GroupId))
|
||||
GroupId = null;
|
||||
|
||||
if (GroupId != null)
|
||||
GroupId = ActiveDirectory.Context.ManagedGroups.ValidateGroupId(GroupId, GroupKey);
|
||||
|
||||
if (GroupId == null)
|
||||
return null;
|
||||
else
|
||||
return JsonConvert.SerializeObject(new ADManagedGroupConfiguration()
|
||||
{
|
||||
GroupId = GroupId,
|
||||
FilterBeginDate = FilterBeginDate
|
||||
}, new JsonSerializerSettings() { DefaultValueHandling = DefaultValueHandling.Ignore });
|
||||
}
|
||||
|
||||
public abstract void Dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADManagedGroupsSyncTask : ScheduledTask
|
||||
{
|
||||
public override string TaskName { get { return "Active Directory - Synchronise Managed Groups"; } }
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext Database)
|
||||
{
|
||||
// ADManagedGroupsSyncTask @ 11:00pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 0));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
int changeCount;
|
||||
|
||||
List<ADManagedGroup> managedGroups = this.ExecutionContext.JobDetail.JobDataMap["ManagedGroups"] as List<ADManagedGroup>;
|
||||
if (managedGroups == null)
|
||||
managedGroups = ActiveDirectory.Context.ManagedGroups.Values;
|
||||
|
||||
this.Status.UpdateStatus(0, "Synchronising Active Directory Managed Groups", "Starting");
|
||||
|
||||
changeCount = ActiveDirectory.Context.ManagedGroups.SyncManagedGroups(managedGroups, this.Status);
|
||||
|
||||
SystemLog.LogInformation(new string[]
|
||||
{
|
||||
"Synchronised Active Directory Managed Groups",
|
||||
changeCount.ToString()
|
||||
});
|
||||
this.Status.SetFinishedMessage(string.Format("Made {0} Changes to Active Directory Groups", changeCount));
|
||||
}
|
||||
|
||||
public static ScheduledTaskStatus ScheduleSync(ADManagedGroup ManagedGroup)
|
||||
{
|
||||
if (ManagedGroup == null)
|
||||
throw new ArgumentNullException("ManagedGroup");
|
||||
|
||||
JobDataMap taskData = new JobDataMap() {
|
||||
{"ManagedGroups", new List<ADManagedGroup> { ManagedGroup } }
|
||||
};
|
||||
|
||||
var instance = new ADManagedGroupsSyncTask();
|
||||
return instance.ScheduleTask(taskData);
|
||||
}
|
||||
public static ScheduledTaskStatus ScheduleSync(IEnumerable<ADManagedGroup> ManagedGroups)
|
||||
{
|
||||
if (ManagedGroups == null)
|
||||
throw new ArgumentNullException("ManagedGroups");
|
||||
|
||||
JobDataMap taskData = new JobDataMap() {
|
||||
{"ManagedGroups", ManagedGroups.ToList() }
|
||||
};
|
||||
|
||||
var instance = new ADManagedGroupsSyncTask();
|
||||
return instance.ScheduleTask(taskData);
|
||||
}
|
||||
public static ScheduledTaskStatus ScheduleSyncAll()
|
||||
{
|
||||
var instance = new ADManagedGroupsSyncTask();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-10
@@ -12,16 +12,15 @@ using System.Linq;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
public class ADTaskUpdateNetworkLogonDates : ScheduledTask
|
||||
public class ADNetworkLogonDatesUpdateTask : 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
|
||||
// ADNetworkLogonDatesUpdateTask @ 11:30pm
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().
|
||||
WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(23, 30));
|
||||
|
||||
@@ -50,11 +49,11 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
public static ScheduledTaskStatus ScheduleImmediately()
|
||||
{
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ADTaskUpdateNetworkLogonDates)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
var existingTask = ScheduledTasks.GetTaskStatuses(typeof(ADNetworkLogonDatesUpdateTask)).Where(s => s.IsRunning).FirstOrDefault();
|
||||
if (existingTask != null)
|
||||
return existingTask;
|
||||
|
||||
var instance = new ADTaskUpdateNetworkLogonDates();
|
||||
var instance = new ADNetworkLogonDatesUpdateTask();
|
||||
return instance.ScheduleTask();
|
||||
}
|
||||
|
||||
@@ -68,16 +67,18 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
if (!string.IsNullOrEmpty(Device.DeviceDomainId) && Device.DeviceDomainId.Contains('\\'))
|
||||
{
|
||||
var context = ActiveDirectory.Context;
|
||||
var deviceSamAccountName = UserExtensions.SplitUserId(Device.DeviceDomainId).Item2 + "$";
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ADHelpers.EscapeLdapQuery(deviceSamAccountName));
|
||||
string deviceSamAccountName;
|
||||
ADDomain deviceDomain;
|
||||
|
||||
var domain = context.GetDomainFromId(Device.DeviceDomainId);
|
||||
ActiveDirectory.ParseDomainAccountId(Device.DeviceDomainId + "$", out deviceSamAccountName, out deviceDomain);
|
||||
|
||||
var ldapFilter = string.Format(ldapFilterTemplate, ADHelpers.EscapeLdapQuery(deviceSamAccountName));
|
||||
IEnumerable<ADDomainController> domainControllers;
|
||||
|
||||
if (context.SearchAllForestServers)
|
||||
domainControllers = domain.GetAllReachableDomainControllers();
|
||||
domainControllers = deviceDomain.GetAllReachableDomainControllers();
|
||||
else
|
||||
domainControllers = domain.GetReachableSiteDomainControllers();
|
||||
domainControllers = deviceDomain.GetReachableSiteDomainControllers();
|
||||
|
||||
lastLogon = domainControllers.Select(dc =>
|
||||
{
|
||||
@@ -111,32 +111,41 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
additionalProperties);
|
||||
}
|
||||
|
||||
[Obsolete("Use generic equivalents: GetPropertyValue<T>(string PropertyName)")]
|
||||
public object GetPropertyValue(string PropertyName, int Index = 0)
|
||||
{
|
||||
return GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
|
||||
}
|
||||
public T GetPropertyValue<T>(string PropertyName)
|
||||
{
|
||||
return GetPropertyValues<T>(PropertyName).FirstOrDefault();
|
||||
}
|
||||
public IEnumerable<T> GetPropertyValues<T>(string PropertyName)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return this.Name;
|
||||
return new string[] { this.Name }.OfType<T>();
|
||||
case "samaccountname":
|
||||
return this.SamAccountName;
|
||||
return new string[] { this.SamAccountName }.OfType<T>();
|
||||
case "distinguishedname":
|
||||
return this.DistinguishedName;
|
||||
return new string[] { this.DistinguishedName }.OfType<T>();
|
||||
case "objectsid":
|
||||
return this.SecurityIdentifier.ToString();
|
||||
return new SecurityIdentifier[] { this.SecurityIdentifier }.OfType<T>();
|
||||
case "sn":
|
||||
return this.Surname;
|
||||
return new string[] { this.Surname }.OfType<T>();
|
||||
case "givenname":
|
||||
return this.GivenName;
|
||||
return new string[] { this.GivenName }.OfType<T>();
|
||||
case "mail":
|
||||
return this.Email;
|
||||
return new string[] { this.Email }.OfType<T>();
|
||||
case "telephonenumber":
|
||||
return this.Phone;
|
||||
return new string[] { this.Phone }.OfType<T>();
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
if (this.LoadedProperties.TryGetValue(PropertyName, out adProperty))
|
||||
return adProperty.OfType<T>();
|
||||
else
|
||||
return null;
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -114,23 +114,23 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
#region Groups
|
||||
|
||||
public static ADGroup RetrieveADGroup(string Id)
|
||||
public static ADGroup RetrieveADGroup(string Id, params string[] AdditionalProperties)
|
||||
{
|
||||
var domain = Context.GetDomainFromId(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroup(Id);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroup(Id, AdditionalProperties);
|
||||
}
|
||||
public static ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName)
|
||||
public static ADGroup RetrieveADGroupByDistinguishedName(string DistinguishedName, params string[] AdditionalProperties)
|
||||
{
|
||||
var domain = Context.GetDomainFromDistinguishedName(DistinguishedName);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupByDistinguishedName(DistinguishedName);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupByDistinguishedName(DistinguishedName, AdditionalProperties);
|
||||
}
|
||||
public static ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier)
|
||||
public static ADGroup RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier SecurityIdentifier, params string[] AdditionalProperties)
|
||||
{
|
||||
var domain = Context.GetDomainFromSecurityIdentifier(SecurityIdentifier);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier);
|
||||
return domain.GetAvailableDomainController().RetrieveADGroupWithSecurityIdentifier(SecurityIdentifier, AdditionalProperties);
|
||||
}
|
||||
|
||||
public static IEnumerable<ADGroup> SearchADGroups(string Term, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit)
|
||||
public static IEnumerable<ADGroup> SearchADGroups(string Term, int? ResultLimit = ActiveDirectory.DefaultSearchResultLimit, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Term))
|
||||
throw new ArgumentNullException("Term");
|
||||
@@ -141,7 +141,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
if (string.IsNullOrWhiteSpace(term))
|
||||
return Enumerable.Empty<ADGroup>();
|
||||
|
||||
var ldapFilter= string.Format(ADGroup.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
|
||||
var ldapFilter = string.Format(ADGroup.LdapSearchFilterTemplate, ADHelpers.EscapeLdapQuery(term));
|
||||
|
||||
IEnumerable<ADSearchResult> searchResults;
|
||||
if (searchDomain != null)
|
||||
@@ -149,7 +149,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
else
|
||||
searchResults = Context.SearchScope(ldapFilter, ADGroup.LoadProperties, ResultLimit);
|
||||
|
||||
return searchResults.Select(result => result.AsADGroup());
|
||||
return searchResults.Select(result => result.AsADGroup(AdditionalProperties));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -185,6 +185,124 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
#region Helpers
|
||||
|
||||
public static string ParseDomainAccountId(string AccountId)
|
||||
{
|
||||
return ParseDomainAccountId(AccountId, null);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, string AccountDomain)
|
||||
{
|
||||
string accountUsername;
|
||||
ADDomain domain;
|
||||
|
||||
return ParseDomainAccountId(AccountId, AccountDomain, out accountUsername, out domain);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, out string AccountUsername)
|
||||
{
|
||||
return ParseDomainAccountId(AccountId, null, out AccountUsername);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, string AccountDomain, out string AccountUsername)
|
||||
{
|
||||
ADDomain domain;
|
||||
|
||||
return ParseDomainAccountId(AccountId, AccountDomain, out AccountUsername, out domain);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, out ADDomain Domain)
|
||||
{
|
||||
return ParseDomainAccountId(AccountId, null, out Domain);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, string AccountDomain, out ADDomain Domain)
|
||||
{
|
||||
string accountUsername;
|
||||
|
||||
return ParseDomainAccountId(AccountId, AccountDomain, out accountUsername, out Domain);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, out string AccountUsername, out ADDomain Domain)
|
||||
{
|
||||
return ParseDomainAccountId(AccountId, null, out AccountUsername, out Domain);
|
||||
}
|
||||
public static string ParseDomainAccountId(string AccountId, string AccountDomain, out string AccountUsername, out ADDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(AccountId))
|
||||
throw new ArgumentNullException("AccountId");
|
||||
|
||||
var slashIndex = AccountId.IndexOf('\\');
|
||||
|
||||
if (slashIndex < 0 && !string.IsNullOrWhiteSpace(AccountDomain))
|
||||
{
|
||||
AccountId = AccountDomain + @"\" + AccountId;
|
||||
slashIndex = AccountDomain.Length;
|
||||
}
|
||||
|
||||
if (slashIndex < 0)
|
||||
{
|
||||
AccountUsername = AccountId;
|
||||
Domain = Context.PrimaryDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountUsername = AccountId.Substring(slashIndex + 1);
|
||||
Domain = Context.GetDomainByNetBiosName(AccountId.Substring(0, slashIndex));
|
||||
}
|
||||
|
||||
return string.Concat(Domain.NetBiosName, @"\", AccountUsername);
|
||||
}
|
||||
|
||||
public static bool IsValidDomainAccountId(string AccountId)
|
||||
{
|
||||
string accountUsername;
|
||||
ADDomain domain;
|
||||
|
||||
return IsValidDomainAccountId(AccountId, out accountUsername, out domain);
|
||||
}
|
||||
public static bool IsValidDomainAccountId(string AccountId, out string AccountUsername)
|
||||
{
|
||||
ADDomain domain;
|
||||
|
||||
return IsValidDomainAccountId(AccountId, out AccountUsername, out domain);
|
||||
}
|
||||
public static bool IsValidDomainAccountId(string AccountId, out ADDomain Domain)
|
||||
{
|
||||
string accountUsername;
|
||||
|
||||
return IsValidDomainAccountId(AccountId, out accountUsername, out Domain);
|
||||
}
|
||||
public static bool IsValidDomainAccountId(string AccountId, out string AccountUsername, out ADDomain Domain)
|
||||
{
|
||||
if (string.IsNullOrEmpty(AccountId))
|
||||
{
|
||||
AccountUsername = null;
|
||||
Domain = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var slashIndex = AccountId.IndexOf('\\');
|
||||
if (slashIndex < 0)
|
||||
{
|
||||
AccountUsername = AccountId;
|
||||
Domain = null;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
AccountUsername = AccountId.Substring(slashIndex + 1);
|
||||
return ActiveDirectory.Context.TryGetDomainByNetBiosName(AccountId.Substring(0, slashIndex), out Domain);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the AccountId Domain matches the Primary Domain, returns the Account Username without the Domain specified
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string FriendlyAccountId(string AccountId)
|
||||
{
|
||||
var slashIndex = AccountId.IndexOf('\\');
|
||||
|
||||
if (slashIndex > 0 && AccountId.Substring(0, slashIndex).Equals(ActiveDirectory.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
|
||||
return AccountId.Substring(slashIndex + 1);
|
||||
else
|
||||
return AccountId;
|
||||
}
|
||||
|
||||
private static string RelevantSearchTerm(string Term, out ADDomain Domain)
|
||||
{
|
||||
Domain = null;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
public ADSite Site { get; private set; }
|
||||
public ADDomain PrimaryDomain { get; private set; }
|
||||
public List<ADDomain> Domains { get; private set; }
|
||||
public ActiveDirectoryManagedGroups ManagedGroups { get; private set; }
|
||||
|
||||
public List<string> ForestServers
|
||||
{
|
||||
@@ -39,7 +40,12 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
|
||||
#region Contructor/Initializing
|
||||
|
||||
internal ActiveDirectoryContext(DiscoDataContext Database)
|
||||
private ActiveDirectoryContext()
|
||||
{
|
||||
ManagedGroups = new ActiveDirectoryManagedGroups();
|
||||
}
|
||||
|
||||
internal ActiveDirectoryContext(DiscoDataContext Database) : this()
|
||||
{
|
||||
Initialize(Database);
|
||||
}
|
||||
@@ -138,24 +144,24 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
var slashIndex = Id.IndexOf('\\');
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
if (slashIndex < 0)
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
return TryGetDomainByNetBiosName(idSplit.Item1, out Domain);
|
||||
return TryGetDomainByNetBiosName(Id.Substring(0, slashIndex), out Domain);
|
||||
}
|
||||
public ADDomain GetDomainFromId(string Id)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Id))
|
||||
throw new ArgumentNullException("Id");
|
||||
|
||||
var idSplit = UserExtensions.SplitUserId(Id);
|
||||
var slashIndex = Id.IndexOf('\\');
|
||||
|
||||
if (string.IsNullOrWhiteSpace(idSplit.Item1))
|
||||
if (slashIndex < 0)
|
||||
throw new ArgumentException(string.Format("The Id must include the Domain [{0}]", Id), "Id");
|
||||
|
||||
return GetDomainByNetBiosName(idSplit.Item1);
|
||||
return GetDomainByNetBiosName(Id.Substring(0, slashIndex));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -69,21 +69,21 @@ namespace Disco.Services.Interop.ActiveDirectory
|
||||
}
|
||||
|
||||
// Groups
|
||||
public static ADGroup AsADGroup(this ADSearchResult SearchResult)
|
||||
public static ADGroup AsADGroup(this ADSearchResult SearchResult, string[] AdditionalProperties)
|
||||
{
|
||||
return ADGroup.FromSearchResult(SearchResult);
|
||||
return ADGroup.FromSearchResult(SearchResult, AdditionalProperties);
|
||||
}
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADSearchResult> SearchResults)
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADSearchResult> SearchResults, string[] AdditionalProperties)
|
||||
{
|
||||
return SearchResults.Select(sr => ADGroup.FromSearchResult(sr));
|
||||
return SearchResults.Select(sr => ADGroup.FromSearchResult(sr, AdditionalProperties));
|
||||
}
|
||||
public static ADGroup AsADGroup(this ADDirectoryEntry DirectoryEntry)
|
||||
public static ADGroup AsADGroup(this ADDirectoryEntry DirectoryEntry, string[] AdditionalProperties)
|
||||
{
|
||||
return ADGroup.FromDirectoryEntry(DirectoryEntry);
|
||||
return ADGroup.FromDirectoryEntry(DirectoryEntry, AdditionalProperties);
|
||||
}
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADDirectoryEntry> DirectoryEntries)
|
||||
public static IEnumerable<ADGroup> AsADGroups(this IEnumerable<ADDirectoryEntry> DirectoryEntries, string[] AdditionalProperties)
|
||||
{
|
||||
return DirectoryEntries.Select(de => ADGroup.FromDirectoryEntry(de));
|
||||
return DirectoryEntries.Select(de => ADGroup.FromDirectoryEntry(de, AdditionalProperties));
|
||||
}
|
||||
|
||||
// Organisational Units
|
||||
|
||||
@@ -0,0 +1,483 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.Services.Interop.ActiveDirectory
|
||||
{
|
||||
using Disco.Services.Logging;
|
||||
using Disco.Services.Tasks;
|
||||
using ScheduledActionItemGrouping = List<Tuple<ADManagedGroup, List<ADManagedGroupScheduledActionItem>>>;
|
||||
|
||||
public class ActiveDirectoryManagedGroups : IDisposable
|
||||
{
|
||||
private ConcurrentDictionary<string, ADManagedGroup> managedGroups;
|
||||
private Subject<ADManagedGroupScheduledAction> actionBuffer;
|
||||
private IDisposable actionBufferSubscription;
|
||||
|
||||
internal ActiveDirectoryManagedGroups()
|
||||
{
|
||||
managedGroups = new ConcurrentDictionary<string, ADManagedGroup>();
|
||||
actionBuffer = new Subject<ADManagedGroupScheduledAction>();
|
||||
|
||||
// Subscribe, wait for no additional actions after 10 seconds
|
||||
actionBufferSubscription = actionBuffer
|
||||
.BufferWithInactivity(TimeSpan.FromSeconds(10))
|
||||
.Subscribe(ParseScheduledActions);
|
||||
}
|
||||
|
||||
#region Collection Methods
|
||||
public void AddOrUpdate(ADManagedGroup ManagedGroup)
|
||||
{
|
||||
ManagedGroup.Context = this;
|
||||
ManagedGroup.Initialize();
|
||||
|
||||
string key = ManagedGroup.Key;
|
||||
|
||||
var existingGroup = managedGroups.Values
|
||||
.Where(g => g.Key != ManagedGroup.Key)
|
||||
.FirstOrDefault(g => g.Configuration.GroupId.Equals(ManagedGroup.Configuration.GroupId, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (existingGroup != null)
|
||||
throw new ArgumentException(string.Format("[{0}] cannot manage this group [{1}] because is already managed by [{2}]", ManagedGroup.Key, ManagedGroup.Configuration.GroupId, existingGroup.Key), "ManagedGroup");
|
||||
|
||||
managedGroups.AddOrUpdate(key, ManagedGroup, (itemKey, item) =>
|
||||
{
|
||||
item.Dispose();
|
||||
return ManagedGroup;
|
||||
});
|
||||
}
|
||||
public bool Remove(string Key)
|
||||
{
|
||||
ADManagedGroup item;
|
||||
|
||||
if (managedGroups.TryRemove(Key, out item))
|
||||
{
|
||||
item.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
public bool TryGetValue(string Key, out ADManagedGroup ManagedGroup)
|
||||
{
|
||||
return managedGroups.TryGetValue(Key, out ManagedGroup);
|
||||
}
|
||||
public List<ADManagedGroup> Values
|
||||
{
|
||||
get
|
||||
{
|
||||
return managedGroups.Values.ToList();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public string ValidateGroupId(string GroupId, string IgnoreManagedGroupKey)
|
||||
{
|
||||
var group = ActiveDirectory.RetrieveADGroup(GroupId, "isCriticalSystemObject");
|
||||
if (group == null)
|
||||
throw new ArgumentException(string.Format("The group [{0}] wasn't found", GroupId), "DevicesLinkedGroup");
|
||||
if (group.GetPropertyValue<bool>("isCriticalSystemObject"))
|
||||
throw new ArgumentException(string.Format("The group [{0}] is a Critical System Active Directory Object and Disco refuses to modify it", group.DistinguishedName), "DevicesLinkedGroup");
|
||||
|
||||
GroupId = group.Id;
|
||||
|
||||
var otherManagedGroup = ActiveDirectory.Context.ManagedGroups.Values
|
||||
.Where(g => g.Key != IgnoreManagedGroupKey)
|
||||
.FirstOrDefault(g => g.Configuration.GroupId.Equals(GroupId, StringComparison.OrdinalIgnoreCase));
|
||||
if (otherManagedGroup != null)
|
||||
throw new ArgumentException(string.Format("Cannot manage this group [{0}] because is already managed by [{1}]", GroupId, otherManagedGroup.Key), "DevicesLinkedGroup");
|
||||
|
||||
return GroupId;
|
||||
}
|
||||
|
||||
internal void ScheduleAction(ADManagedGroupScheduledAction ScheduledAction)
|
||||
{
|
||||
actionBuffer.OnNext(ScheduledAction);
|
||||
}
|
||||
|
||||
private void ParseScheduledActions(IEnumerable<ADManagedGroupScheduledAction> Actions)
|
||||
{
|
||||
ScheduledActionItemGrouping groupedActionItems;
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
{
|
||||
groupedActionItems = Actions
|
||||
.GroupBy(a => a.ManagedGroup)
|
||||
.Where(g =>
|
||||
{
|
||||
ADManagedGroup item;
|
||||
if (managedGroups.TryGetValue(g.Key.Key, out item))
|
||||
return item == g.Key;
|
||||
else
|
||||
return false;
|
||||
})
|
||||
.Select(g => // Reduce actions to last instance of ActionSubjectId
|
||||
Tuple.Create(
|
||||
g.Key,
|
||||
g.GroupBy(i => i.InvokingIdentifier, (id, idg) => idg.Last())
|
||||
)
|
||||
).Select(g => // Resolve action group members (action subjects)
|
||||
Tuple.Create(g.Item1, g.Item2.SelectMany(i => i.ResolveMembers(Database)))
|
||||
).Select(g => // Reduce actions to last instance of MemberId
|
||||
Tuple.Create(
|
||||
g.Item1,
|
||||
g.Item2.GroupBy(i => i.MemberId, (id, idg) => idg.Last()).ToList()
|
||||
)
|
||||
).ToList();
|
||||
}
|
||||
|
||||
ApplyScheduledActionItems(groupedActionItems);
|
||||
}
|
||||
|
||||
private void ApplyScheduledActionItems(ScheduledActionItemGrouping ActionGroups)
|
||||
{
|
||||
var actionsCount = ActionGroups.SelectMany(a => a.Item2).Count();
|
||||
if (actionsCount > 0)
|
||||
{
|
||||
var adSearchLoadProperties = new string[] { "distinguishedName", "sAMAccountName" };
|
||||
var accountDNCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
if (actionsCount > 40)
|
||||
{
|
||||
// Potentially over 40 accounts, cache all scoped
|
||||
var scopeAccounts = ActiveDirectory.Context.SearchScope("(|(objectCategory=computer)(objectCategory=person))", adSearchLoadProperties);
|
||||
foreach (var scopeAccount in scopeAccounts)
|
||||
{
|
||||
var id = string.Format(@"{0}\{1}", scopeAccount.Domain.NetBiosName, scopeAccount.Value<string>("sAMAccountName"));
|
||||
accountDNCache[id] = scopeAccount.Value<string>("distinguishedName");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var actionGroup in ActionGroups)
|
||||
{
|
||||
// Resolve Member Ids to AD Distinguished Names
|
||||
// Discard non-existent users
|
||||
var actionItems = actionGroup.Item2.Select(a =>
|
||||
{
|
||||
string distinguishedName;
|
||||
if (!accountDNCache.TryGetValue(a.MemberId, out distinguishedName))
|
||||
{
|
||||
string memberUsername;
|
||||
ADDomain memberDomain;
|
||||
if (!ActiveDirectory.IsValidDomainAccountId(a.MemberId, out memberUsername, out memberDomain))
|
||||
{
|
||||
accountDNCache[a.MemberId] = null; // Add to cache (avoid retries)
|
||||
return null;
|
||||
}
|
||||
|
||||
var ldapFilter = string.Format("(&(|(objectCategory=computer)(objectCategory=person))(sAMAccountName={0}))", memberUsername);
|
||||
|
||||
var adSearchResult = memberDomain.SearchEntireDomain(ldapFilter, adSearchLoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
if (adSearchResult != null)
|
||||
{
|
||||
var adSearchResultDN = adSearchResult.Value<string>("distinguishedName");
|
||||
accountDNCache[a.MemberId] = adSearchResultDN; // Add to cache
|
||||
a.MemberDistinguishedName = adSearchResultDN; // Update ActionItem
|
||||
return a;
|
||||
}
|
||||
else
|
||||
{
|
||||
accountDNCache[a.MemberId] = null; // Add to cache (avoid retries)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (distinguishedName == null)
|
||||
return null;
|
||||
else
|
||||
{
|
||||
a.MemberDistinguishedName = distinguishedName; // Update ActionItem
|
||||
return a;
|
||||
}
|
||||
}).Where(a => a != null).ToList();
|
||||
|
||||
if (actionItems.Count > 0)
|
||||
{
|
||||
var adGroup = actionGroup.Item1.GetGroup();
|
||||
if (adGroup == null)
|
||||
{
|
||||
SystemLog.LogWarning("Active Directory Managed Group", actionGroup.Item1.Key, "Group Not Found", actionGroup.Item1.Configuration.GroupId);
|
||||
break;
|
||||
}
|
||||
var adGroupMembers = adGroup.GetPropertyValues<string>("member").ToList();
|
||||
actionItems = actionItems.Where(a =>
|
||||
{
|
||||
switch (a.ActionType)
|
||||
{
|
||||
case ADManagedGroupScheduledActionType.AddGroupMember:
|
||||
return !adGroupMembers.Contains(a.MemberDistinguishedName);
|
||||
case ADManagedGroupScheduledActionType.RemoveGroupMember:
|
||||
return adGroupMembers.Contains(a.MemberDistinguishedName);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}).ToList();
|
||||
|
||||
if (actionItems.Count > 0)
|
||||
{
|
||||
using (var adGroupEntry = ActiveDirectory.Context.RetrieveDirectoryEntry(adGroup.DistinguishedName, new string[] { "member", "isCriticalSystemObject" }))
|
||||
{
|
||||
if (adGroupEntry.Entry.Properties.Value<bool>("isCriticalSystemObject"))
|
||||
throw new InvalidOperationException(string.Format("This group [{0}] is a Critical System Active Directory Object and Disco refuses to modify it", adGroup.DistinguishedName));
|
||||
|
||||
var adGroupEntryMembers = adGroupEntry.Entry.Properties["member"];
|
||||
foreach (var item in actionItems)
|
||||
{
|
||||
switch (item.ActionType)
|
||||
{
|
||||
case ADManagedGroupScheduledActionType.AddGroupMember:
|
||||
if (!adGroupEntryMembers.Contains(item.MemberDistinguishedName))
|
||||
{
|
||||
// Add Member Entry
|
||||
adGroupEntryMembers.Add(item.MemberDistinguishedName);
|
||||
}
|
||||
break;
|
||||
case ADManagedGroupScheduledActionType.RemoveGroupMember:
|
||||
if (adGroupEntryMembers.Contains(item.MemberDistinguishedName))
|
||||
{
|
||||
// Add Member Entry
|
||||
adGroupEntryMembers.Remove(item.MemberDistinguishedName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Commit Changes
|
||||
adGroupEntry.Entry.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int SyncManagedGroups(IScheduledTaskStatus Status)
|
||||
{
|
||||
return SyncManagedGroups(managedGroups.Values, Status);
|
||||
}
|
||||
|
||||
public int SyncManagedGroups(ADManagedGroup ManagedGroup, IScheduledTaskStatus Status)
|
||||
{
|
||||
return SyncManagedGroups(new ADManagedGroup[] { ManagedGroup }, Status);
|
||||
}
|
||||
|
||||
public int SyncManagedGroups(IEnumerable<ADManagedGroup> ManagedGroups, IScheduledTaskStatus Status)
|
||||
{
|
||||
List<ADManagedGroup> managedGroups = ManagedGroups.ToList();
|
||||
ScheduledActionItemGrouping actionGroups;
|
||||
int changeCount = 0;
|
||||
|
||||
Status.UpdateStatus(0, "Determining Managed Group Members");
|
||||
|
||||
using (DiscoDataContext Database = new DiscoDataContext())
|
||||
{
|
||||
actionGroups = managedGroups.Select((g, index) =>
|
||||
{
|
||||
Status.UpdateStatus(
|
||||
((double)30 / managedGroups.Count) * index, // 0 -> 30
|
||||
string.Format("Determining Group Members: {0} [{1}]", g.GroupDescription, g.Configuration.GroupId));
|
||||
return Tuple.Create(
|
||||
g,
|
||||
g.DetermineMembers(Database).Select(m =>
|
||||
new ADManagedGroupScheduledActionItem(
|
||||
g,
|
||||
ADManagedGroupScheduledActionType.AddGroupMember,
|
||||
m
|
||||
)).ToList());
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
var actionsCount = actionGroups.SelectMany(a => a.Item2).Count();
|
||||
if (actionsCount > 0)
|
||||
{
|
||||
Status.UpdateStatus(30, "Resolving Group Members");
|
||||
|
||||
var adSearchLoadProperties = new string[] { "distinguishedName", "sAMAccountName", "displayName", "name" };
|
||||
var accountDNCache = new Dictionary<string, Tuple<string, string>>(StringComparer.OrdinalIgnoreCase);
|
||||
if (actionsCount > 40)
|
||||
{
|
||||
// Potentially over 40 accounts, cache all scoped
|
||||
var scopeAccounts = ActiveDirectory.Context.SearchScope("(|(objectCategory=computer)(objectCategory=person))", adSearchLoadProperties);
|
||||
foreach (var scopeAccount in scopeAccounts)
|
||||
{
|
||||
var id = string.Format(@"{0}\{1}", scopeAccount.Domain.NetBiosName, scopeAccount.Value<string>("sAMAccountName"));
|
||||
accountDNCache[id] = Tuple.Create(scopeAccount.Value<string>("distinguishedName"), scopeAccount.Value<string>("displayName") ?? scopeAccount.Value<string>("name"));
|
||||
}
|
||||
}
|
||||
|
||||
actionGroups = actionGroups.Select((g, index) =>
|
||||
{
|
||||
Status.UpdateStatus(
|
||||
30 + (((double)30 / actionGroups.Count) * index), // 30 -> 60
|
||||
string.Format("Resolving {0} Group Members: {1} [{2}]", g.Item2.Count, g.Item1.GroupDescription, g.Item1.Configuration.GroupId));
|
||||
|
||||
// Resolve Member Ids to AD Distinguished Names
|
||||
// Discard non-existent users
|
||||
return Tuple.Create(
|
||||
g.Item1,
|
||||
g.Item2.Select(a =>
|
||||
{
|
||||
Tuple<string, string> definition;
|
||||
if (!accountDNCache.TryGetValue(a.MemberId, out definition))
|
||||
{
|
||||
string memberUsername;
|
||||
ADDomain memberDomain;
|
||||
if (!ActiveDirectory.IsValidDomainAccountId(a.MemberId, out memberUsername, out memberDomain))
|
||||
{
|
||||
accountDNCache[a.MemberId] = null; // Add to cache (avoid retries)
|
||||
return null;
|
||||
}
|
||||
|
||||
var ldapFilter = string.Format("(&(|(objectCategory=computer)(objectCategory=person))(sAMAccountName={0}))", memberUsername);
|
||||
|
||||
var adSearchResult = memberDomain.SearchEntireDomain(ldapFilter, adSearchLoadProperties, ActiveDirectory.SingleSearchResult).FirstOrDefault();
|
||||
if (adSearchResult != null)
|
||||
{
|
||||
definition = Tuple.Create(adSearchResult.Value<string>("distinguishedName"), adSearchResult.Value<string>("displayName") ?? adSearchResult.Value<string>("name"));
|
||||
accountDNCache[a.MemberId] = definition; // Add to cache
|
||||
}
|
||||
else
|
||||
{
|
||||
accountDNCache[a.MemberId] = null; // Add to cache (avoid retries)
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (definition == null)
|
||||
return null;
|
||||
|
||||
a.MemberDistinguishedName = definition.Item1; // Update ActionItem
|
||||
a.MemberDisplayName = definition.Item2;
|
||||
return a;
|
||||
}).Where(a => a != null).ToList());
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
foreach (var actionGroup in actionGroups)
|
||||
{
|
||||
var adGroup = actionGroup.Item1.GetGroup();
|
||||
if (adGroup == null)
|
||||
{
|
||||
SystemLog.LogWarning("Active Directory Managed Group", actionGroup.Item1.Key, "Group Not Found", actionGroup.Item1.Configuration.GroupId);
|
||||
break;
|
||||
}
|
||||
|
||||
Status.UpdateStatus(
|
||||
60 + (((double)40 / actionGroups.Count) * actionGroups.IndexOf(actionGroup)), // 60 -> 100
|
||||
string.Format("Synchronizing {0} Group Members: {1} [{2}]", actionGroup.Item2.Count, actionGroup.Item1.GroupDescription, actionGroup.Item1.Configuration.GroupId));
|
||||
|
||||
using (var adGroupEntry = ActiveDirectory.Context.RetrieveDirectoryEntry(adGroup.DistinguishedName, new string[] { "isCriticalSystemObject", "description", "member" }))
|
||||
{
|
||||
if (adGroupEntry.Entry.Properties.Value<bool>("isCriticalSystemObject"))
|
||||
throw new InvalidOperationException(string.Format("This group [{0}] is a Critical System Active Directory Object and Disco refuses to modify it", adGroup.DistinguishedName));
|
||||
|
||||
// Update Description
|
||||
var groupDescription = string.Format("Disco ICT: {0}", actionGroup.Item1.GroupDescription);
|
||||
if (adGroupEntry.Entry.Properties.Value<string>("description") != groupDescription)
|
||||
{
|
||||
var adGroupEntryDescription = adGroupEntry.Entry.Properties["description"];
|
||||
if (adGroupEntryDescription.Count > 0)
|
||||
adGroupEntryDescription.Clear();
|
||||
adGroupEntryDescription.Add(groupDescription);
|
||||
}
|
||||
|
||||
// Sync Members
|
||||
var adGroupEntryMembers = adGroupEntry.Entry.Properties["member"];
|
||||
|
||||
// Remove Items
|
||||
var removeItems = adGroupEntryMembers
|
||||
.Cast<string>()
|
||||
.Except(actionGroup.Item2.Select(i => i.MemberDistinguishedName))
|
||||
.ToList();
|
||||
removeItems.ForEach(i => adGroupEntryMembers.Remove(i));
|
||||
|
||||
// Add Items
|
||||
var addItems = actionGroup.
|
||||
Item2.Select(i => i.MemberDistinguishedName)
|
||||
.Except(adGroupEntryMembers.Cast<string>())
|
||||
.ToList();
|
||||
addItems.ForEach(i => adGroupEntryMembers.Add(i));
|
||||
|
||||
// Commit Changes
|
||||
adGroupEntry.Entry.CommitChanges();
|
||||
|
||||
changeCount += removeItems.Count;
|
||||
changeCount += addItems.Count;
|
||||
}
|
||||
}
|
||||
|
||||
Status.UpdateStatus(100, "Managed Group Synchronization Finished");
|
||||
|
||||
return changeCount;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (actionBufferSubscription != null)
|
||||
actionBufferSubscription.Dispose();
|
||||
|
||||
if (actionBuffer != null)
|
||||
actionBuffer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal class ADManagedGroupScheduledAction
|
||||
{
|
||||
private Func<DiscoDataContext, IEnumerable<string>> memberResolver;
|
||||
|
||||
public ADManagedGroup ManagedGroup { get; private set; }
|
||||
public ADManagedGroupScheduledActionType ActionType { get; private set; }
|
||||
public string InvokingIdentifier { get; set; }
|
||||
|
||||
public ADManagedGroupScheduledAction(ADManagedGroup ManagedGroup, ADManagedGroupScheduledActionType ActionType, string InvokingIdentifier, Func<DiscoDataContext, IEnumerable<string>> MemberResolver)
|
||||
{
|
||||
this.ManagedGroup = ManagedGroup;
|
||||
this.ActionType = ActionType;
|
||||
this.InvokingIdentifier = InvokingIdentifier;
|
||||
this.memberResolver = MemberResolver;
|
||||
}
|
||||
|
||||
public IEnumerable<ADManagedGroupScheduledActionItem> ResolveMembers(DiscoDataContext Database)
|
||||
{
|
||||
if (memberResolver != null)
|
||||
{
|
||||
var members = memberResolver(Database);
|
||||
if (members == null)
|
||||
return Enumerable.Empty<ADManagedGroupScheduledActionItem>();
|
||||
else
|
||||
return members.Select(m =>
|
||||
new ADManagedGroupScheduledActionItem(this.ManagedGroup, this.ActionType, m)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ADManagedGroupScheduledActionItem[]
|
||||
{
|
||||
new ADManagedGroupScheduledActionItem(this.ManagedGroup, this.ActionType, this.InvokingIdentifier)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
internal class ADManagedGroupScheduledActionItem
|
||||
{
|
||||
public ADManagedGroup ManagedGroup { get; private set; }
|
||||
public ADManagedGroupScheduledActionType ActionType { get; private set; }
|
||||
public string MemberId { get; set; }
|
||||
public string MemberDistinguishedName { get; set; }
|
||||
public string MemberDisplayName { get; set; }
|
||||
|
||||
public ADManagedGroupScheduledActionItem(ADManagedGroup ManagedGroup, ADManagedGroupScheduledActionType ActionType, string MemberId)
|
||||
{
|
||||
this.ManagedGroup = ManagedGroup;
|
||||
this.ActionType = ActionType;
|
||||
this.MemberId = MemberId;
|
||||
}
|
||||
}
|
||||
internal enum ADManagedGroupScheduledActionType
|
||||
{
|
||||
AddGroupMember,
|
||||
RemoveGroupMember
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -63,12 +63,12 @@ namespace Disco.Services
|
||||
i.UserId = j.UserId;
|
||||
i.UserDisplayName = j.User.DisplayName;
|
||||
|
||||
i.UserFriendlyId = UserExtensions.FriendlyUserId(j.UserId);
|
||||
i.UserFriendlyId = ActiveDirectory.FriendlyAccountId(j.UserId);
|
||||
}
|
||||
if (j.OpenedTechUser != null)
|
||||
{
|
||||
i.OpenedTechUserId = j.OpenedTechUserId;
|
||||
i.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId);
|
||||
i.OpenedTechUserFriendlyId = ActiveDirectory.FriendlyAccountId(j.OpenedTechUserId);
|
||||
i.OpenedTechUserDisplayName = j.OpenedTechUser.DisplayName;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.JobLists;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Users;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -233,8 +234,8 @@ namespace Disco.Services
|
||||
|
||||
foreach (var j in items)
|
||||
{
|
||||
j.UserFriendlyId =j.UserId == null ? null : UserExtensions.FriendlyUserId(j.UserId);
|
||||
j.OpenedTechUserFriendlyId = UserExtensions.FriendlyUserId(j.OpenedTechUserId);
|
||||
j.UserFriendlyId =j.UserId == null ? null : ActiveDirectory.FriendlyAccountId(j.UserId);
|
||||
j.OpenedTechUserFriendlyId = ActiveDirectory.FriendlyAccountId(j.OpenedTechUserId);
|
||||
|
||||
if (j.DeviceAddressId.HasValue)
|
||||
j.DeviceAddress = Database.DiscoConfiguration.OrganisationAddresses.GetAddress(j.DeviceAddressId.Value).Name;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Disco.Data.Configuration.Modules;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Jobs.Noticeboards;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -17,7 +18,7 @@ namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
get
|
||||
{
|
||||
return DeviceComputerName == null ? null : UserExtensions.FriendlyUserId(DeviceComputerName);
|
||||
return DeviceComputerName == null ? null : ActiveDirectory.FriendlyAccountId(DeviceComputerName);
|
||||
}
|
||||
set { } // for XML Serialization
|
||||
}
|
||||
@@ -67,7 +68,7 @@ namespace Disco.Services.Jobs.Noticeboards
|
||||
{
|
||||
get
|
||||
{
|
||||
return UserId == null ? null : UserExtensions.FriendlyUserId(UserId);
|
||||
return UserId == null ? null : ActiveDirectory.FriendlyAccountId(UserId);
|
||||
}
|
||||
set { } // for XML Serialization
|
||||
}
|
||||
|
||||
@@ -82,9 +82,7 @@ namespace Disco.Services.Jobs.Noticeboards
|
||||
}
|
||||
public static IHeldDeviceItem GetHeldDeviceForUsers(DiscoDataContext Database, string UserId)
|
||||
{
|
||||
var split = UserExtensions.SplitUserId(UserId);
|
||||
if (split.Item1 == null)
|
||||
UserId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, UserId);
|
||||
UserId = ActiveDirectory.ParseDomainAccountId(UserId);
|
||||
|
||||
return GetHeldDevicesForUsers(Database.Devices.Where(d => d.AssignedUserId == UserId).SelectMany(d => d.Jobs)).FirstOrDefault();
|
||||
}
|
||||
|
||||
@@ -235,7 +235,7 @@ namespace Disco.Services.Searching
|
||||
UserFlagAssignments = u.UserFlagAssignments
|
||||
}).ToList();
|
||||
|
||||
results.ForEach(u => u.FriendlyId = UserExtensions.FriendlyUserId(u.Id));
|
||||
results.ForEach(u => u.FriendlyId = ActiveDirectory.FriendlyAccountId(u.Id));
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
@@ -18,26 +18,7 @@ namespace Disco.Services
|
||||
|
||||
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.Context.PrimaryDomain.NetBiosName, StringComparison.OrdinalIgnoreCase))
|
||||
return splitUserId.Item2;
|
||||
else
|
||||
return UserId;
|
||||
}
|
||||
|
||||
public static Tuple<string, string> SplitUserId(string UserId)
|
||||
{
|
||||
var slashIndex = UserId.IndexOf('\\');
|
||||
if (slashIndex < 0)
|
||||
return Tuple.Create<string, string>(null, UserId);
|
||||
else
|
||||
return Tuple.Create(UserId.Substring(0, slashIndex), UserId.Substring(slashIndex + 1));
|
||||
return ActiveDirectory.FriendlyAccountId(u.UserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,28 +42,9 @@ namespace Disco.Services.Users.UserFlags
|
||||
return _Cache.Values.ToList();
|
||||
}
|
||||
|
||||
public UserFlag Update(UserFlag UserFlag)
|
||||
public void AddOrUpdate(UserFlag UserFlag)
|
||||
{
|
||||
UserFlag existingItem;
|
||||
|
||||
if (_Cache.TryGetValue(UserFlag.Id, out existingItem))
|
||||
{
|
||||
if (_Cache.TryUpdate(UserFlag.Id, UserFlag, existingItem))
|
||||
{
|
||||
return UserFlag;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_Cache.TryAdd(UserFlag.Id, UserFlag))
|
||||
{
|
||||
return UserFlag;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
_Cache.AddOrUpdate(UserFlag.Id, UserFlag, (key, existingItem) => UserFlag);
|
||||
}
|
||||
|
||||
public UserFlag Remove(int UserFlagId)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository.Monitor;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Extensions;
|
||||
using Disco.Services.Tasks;
|
||||
@@ -9,16 +10,39 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
namespace Disco.Services.Users.UserFlags
|
||||
{
|
||||
public static class UserFlagService
|
||||
{
|
||||
private static Cache _cache;
|
||||
internal static Lazy<IObservable<RepositoryMonitorEvent>> UserFlagAssignmentRepositoryEvents;
|
||||
|
||||
static UserFlagService()
|
||||
{
|
||||
// Statically defined (lazy) Assignment Repository Definition
|
||||
// Used by UserFlagAssignedUsersManagedGroup & UserFlagAssignedUserDevicesManagedGroup
|
||||
UserFlagAssignmentRepositoryEvents =
|
||||
new Lazy<IObservable<RepositoryMonitorEvent>>(() =>
|
||||
RepositoryMonitor.StreamAfterCommit.Where(e =>
|
||||
e.EntityType == typeof(UserFlagAssignment) &&
|
||||
(e.EventType != RepositoryMonitorEventType.Modified ||
|
||||
e.ModifiedProperties.Contains("RemovedDate"))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static void Initialize(DiscoDataContext Database)
|
||||
{
|
||||
_cache = new Cache(Database);
|
||||
|
||||
// Initialize Managed Groups (if configured)
|
||||
_cache.GetUserFlags().ForEach(uf =>
|
||||
{
|
||||
UserFlagUsersManagedGroup.Initialize(uf);
|
||||
UserFlagUserDevicesManagedGroup.Initialize(uf);
|
||||
});
|
||||
}
|
||||
|
||||
public static List<UserFlag> GetUserFlags() { return _cache.GetUserFlags(); }
|
||||
@@ -41,13 +65,17 @@ namespace Disco.Services.Users.UserFlags
|
||||
Name = UserFlag.Name,
|
||||
Description = UserFlag.Description,
|
||||
Icon = UserFlag.Icon,
|
||||
IconColour = UserFlag.IconColour
|
||||
IconColour = UserFlag.IconColour,
|
||||
UsersLinkedGroup = UserFlag.UsersLinkedGroup,
|
||||
UserDevicesLinkedGroup = UserFlag.UserDevicesLinkedGroup
|
||||
};
|
||||
|
||||
Database.UserFlags.Add(flag);
|
||||
Database.SaveChanges();
|
||||
|
||||
return _cache.Update(flag);
|
||||
_cache.AddOrUpdate(flag);
|
||||
|
||||
return flag;
|
||||
}
|
||||
public static UserFlag Update(DiscoDataContext Database, UserFlag UserFlag)
|
||||
{
|
||||
@@ -61,12 +89,20 @@ namespace Disco.Services.Users.UserFlags
|
||||
|
||||
Database.SaveChanges();
|
||||
|
||||
return _cache.Update(UserFlag);
|
||||
_cache.AddOrUpdate(UserFlag);
|
||||
UserFlagUsersManagedGroup.Initialize(UserFlag);
|
||||
UserFlagUserDevicesManagedGroup.Initialize(UserFlag);
|
||||
|
||||
return UserFlag;
|
||||
}
|
||||
public static void DeleteUserFlag(DiscoDataContext Database, int UserFlagId, IScheduledTaskStatus Status)
|
||||
{
|
||||
UserFlag flag = Database.UserFlags.Find(UserFlagId);
|
||||
|
||||
// Dispose of AD Managed Groups
|
||||
Interop.ActiveDirectory.ActiveDirectory.Context.ManagedGroups.Remove(UserFlagUserDevicesManagedGroup.GetKey(flag));
|
||||
Interop.ActiveDirectory.ActiveDirectory.Context.ManagedGroups.Remove(UserFlagUsersManagedGroup.GetKey(flag));
|
||||
|
||||
// Delete Assignments
|
||||
Status.UpdateStatus(0, string.Format("Removing '{0}' [{1}] User Flag", flag.Name, flag.Id), "Starting");
|
||||
List<UserFlagAssignment> flagAssignments = Database.UserFlagAssignments.Where(fa => fa.UserFlagId == flag.Id).ToList();
|
||||
@@ -94,30 +130,39 @@ namespace Disco.Services.Users.UserFlags
|
||||
{
|
||||
if (Users.Count > 0)
|
||||
{
|
||||
|
||||
double progressInterval;
|
||||
const int databaseChunkSize = 100;
|
||||
string comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
|
||||
|
||||
var addUsers = Users.Where(u => !u.UserFlagAssignments.Any(a => a.UserFlagId == UserFlag.Id && !a.RemovedDate.HasValue)).ToList();
|
||||
|
||||
progressInterval = (double)100 / addUsers.Count;
|
||||
|
||||
var addedUserAssignments = addUsers.Select((user, index) =>
|
||||
var addedUserAssignments = addUsers.Chunk(databaseChunkSize).SelectMany((chunk, chunkIndex) =>
|
||||
{
|
||||
Status.UpdateStatus(index * progressInterval, string.Format("Assigning Flag: {0}", user.ToString()));
|
||||
var chunkIndexOffset = databaseChunkSize * chunkIndex;
|
||||
|
||||
var fa = new UserFlagAssignment()
|
||||
var chunkResults = chunk.Select((user, index) =>
|
||||
{
|
||||
UserFlagId = UserFlag.Id,
|
||||
UserId = user.UserId,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
Comments = comments
|
||||
};
|
||||
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, string.Format("Assigning Flag: {0}", user.ToString()));
|
||||
|
||||
Database.UserFlagAssignments.Add(fa);
|
||||
var fa = new UserFlagAssignment()
|
||||
{
|
||||
UserFlagId = UserFlag.Id,
|
||||
UserId = user.UserId,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
Comments = comments
|
||||
};
|
||||
|
||||
Database.UserFlagAssignments.Add(fa);
|
||||
return fa;
|
||||
}).ToList();
|
||||
|
||||
// Save Chunk Items to Database
|
||||
Database.SaveChanges();
|
||||
return fa;
|
||||
|
||||
return chunkResults;
|
||||
}).Where(fa => fa != null).ToList();
|
||||
|
||||
Status.SetFinishedMessage(string.Format("{0} Users/s Added; {1} User/s Skipped", addUsers.Count, (Users.Count - addUsers.Count)));
|
||||
@@ -134,6 +179,7 @@ namespace Disco.Services.Users.UserFlags
|
||||
public static IEnumerable<UserFlagAssignment> BulkAssignOverrideUsers(DiscoDataContext Database, UserFlag UserFlag, User Technician, string Comments, List<User> Users, IScheduledTaskStatus Status)
|
||||
{
|
||||
double progressInterval;
|
||||
const int databaseChunkSize = 100;
|
||||
string comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
|
||||
|
||||
Status.UpdateStatus(0, "Calculating assignment changes");
|
||||
@@ -147,31 +193,53 @@ namespace Disco.Services.Users.UserFlags
|
||||
progressInterval = (double)100 / (removeAssignments.Count + addUsers.Count);
|
||||
var removedDateTime = DateTime.Now;
|
||||
|
||||
removeAssignments.Select((flagAssignment, index) =>
|
||||
// Remove Assignments
|
||||
removeAssignments.Chunk(databaseChunkSize).SelectMany((chunk, chunkIndex) =>
|
||||
{
|
||||
Status.UpdateStatus(index * progressInterval, string.Format("Removing Flag: {0}", flagAssignment.User.ToString()));
|
||||
flagAssignment.RemovedDate = removedDateTime;
|
||||
flagAssignment.RemovedUserId = Technician.UserId;
|
||||
var chunkIndexOffset = (chunkIndex * databaseChunkSize) + removeAssignments.Count;
|
||||
|
||||
var chunkResults = chunk.Select((flagAssignment, index) =>
|
||||
{
|
||||
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, string.Format("Removing Flag: {0}", flagAssignment.User.ToString()));
|
||||
|
||||
flagAssignment.RemovedDate = removedDateTime;
|
||||
flagAssignment.RemovedUserId = Technician.UserId;
|
||||
|
||||
return flagAssignment;
|
||||
}).ToList();
|
||||
|
||||
// Save Chunk Items to Database
|
||||
Database.SaveChanges();
|
||||
return flagAssignment;
|
||||
|
||||
return chunkResults;
|
||||
}).ToList();
|
||||
|
||||
var addedUserAssignments = addUsers.Select((user, index) =>
|
||||
// Add Assignments
|
||||
var addedUserAssignments = addUsers.Chunk(databaseChunkSize).SelectMany((chunk, chunkIndex) =>
|
||||
{
|
||||
Status.UpdateStatus((removeAssignments.Count + index) * progressInterval, string.Format("Assigning Flag: {0}", user.ToString()));
|
||||
var chunkIndexOffset = (chunkIndex * databaseChunkSize) + removeAssignments.Count;
|
||||
|
||||
var fa = new UserFlagAssignment()
|
||||
var chunkResults = chunk.Select((user, index) =>
|
||||
{
|
||||
UserFlagId = UserFlag.Id,
|
||||
UserId = user.UserId,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
Comments = comments
|
||||
};
|
||||
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, string.Format("Assigning Flag: {0}", user.ToString()));
|
||||
|
||||
Database.UserFlagAssignments.Add(fa);
|
||||
var fa = new UserFlagAssignment()
|
||||
{
|
||||
UserFlagId = UserFlag.Id,
|
||||
UserId = user.UserId,
|
||||
AddedDate = DateTime.Now,
|
||||
AddedUserId = Technician.UserId,
|
||||
Comments = comments
|
||||
};
|
||||
|
||||
Database.UserFlagAssignments.Add(fa);
|
||||
return fa;
|
||||
}).ToList();
|
||||
|
||||
// Save Chunk Items to Database
|
||||
Database.SaveChanges();
|
||||
return fa;
|
||||
|
||||
return chunkResults;
|
||||
}).ToList();
|
||||
|
||||
Status.SetFinishedMessage(string.Format("{0} Users/s Added; {1} User/s Removed; {2} User/s Skipped", addUsers.Count, removeAssignments.Count, (Users.Count - addUsers.Count)));
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
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 false; } }
|
||||
|
||||
private UserFlagUserDevicesManagedGroup(string Key, ADManagedGroupConfiguration Configuration, UserFlag UserFlag)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.UserFlagId = UserFlag.Id;
|
||||
this.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<string> DetermineDeviceMembers(DiscoDataContext Database, string UserId)
|
||||
{
|
||||
return DetermineDeviceMembers(Database.Users.Where(u => u.UserId == UserId));
|
||||
}
|
||||
|
||||
private IEnumerable<string> DetermineDeviceMembers(IQueryable<User> 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<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
var assignments = Database.UserFlagAssignments
|
||||
.Where(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue)
|
||||
.Select(a => a.User);
|
||||
|
||||
return DetermineDeviceMembers(assignments);
|
||||
}
|
||||
|
||||
private void ProcessRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var userFlagAssignemnt = (UserFlagAssignment)Event.Entity;
|
||||
string userId = userFlagAssignemnt.UserId;
|
||||
|
||||
switch (Event.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
if (!userFlagAssignemnt.RemovedDate.HasValue)
|
||||
AddMember(userFlagAssignemnt.UserId, (database) => DetermineDeviceMembers(database, userId));
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (userFlagAssignemnt.RemovedDate.HasValue)
|
||||
RemoveMember(userFlagAssignemnt.UserId, (database) => DetermineDeviceMembers(database, userId));
|
||||
else
|
||||
AddMember(userFlagAssignemnt.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 (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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
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 UserFlagUsersManagedGroup : ADManagedGroup
|
||||
{
|
||||
private const string KeyFormat = "UserFlag_{0}_Users";
|
||||
private const string DescriptionFormat = "User associated with the {0} Flag will be added to this Active Directory group.";
|
||||
private const string CategoryDescriptionFormat = "Assigned Users Linked Group";
|
||||
private const string GroupDescriptionFormat = "{0} [User Flag Users]";
|
||||
|
||||
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 false; } }
|
||||
|
||||
private UserFlagUsersManagedGroup(string Key, ADManagedGroupConfiguration Configuration, UserFlag UserFlag)
|
||||
: base(Key, Configuration)
|
||||
{
|
||||
this.UserFlagId = UserFlag.Id;
|
||||
this.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 UserFlagUsersManagedGroup ManagedGroup)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
string key = GetKey(UserFlag);
|
||||
|
||||
if (ActiveDirectory.Context.ManagedGroups.TryGetValue(key, out managedGroup))
|
||||
{
|
||||
ManagedGroup = (UserFlagUsersManagedGroup)managedGroup;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
ManagedGroup = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static UserFlagUsersManagedGroup Initialize(UserFlag UserFlag)
|
||||
{
|
||||
if (UserFlag.Id > 0)
|
||||
{
|
||||
var key = GetKey(UserFlag);
|
||||
|
||||
if (!string.IsNullOrEmpty(UserFlag.UsersLinkedGroup))
|
||||
{
|
||||
var config = ADManagedGroup.ConfigurationFromJson(UserFlag.UsersLinkedGroup);
|
||||
|
||||
if (config != null && !string.IsNullOrWhiteSpace(config.GroupId))
|
||||
{
|
||||
var group = new UserFlagUsersManagedGroup(
|
||||
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;
|
||||
}
|
||||
|
||||
public override IEnumerable<string> DetermineMembers(DiscoDataContext Database)
|
||||
{
|
||||
return Database.UserFlagAssignments
|
||||
.Where(a => a.UserFlagId == UserFlagId && !a.RemovedDate.HasValue)
|
||||
.Select(a => a.UserId);
|
||||
}
|
||||
|
||||
private void ProcessRepositoryEvent(RepositoryMonitorEvent Event)
|
||||
{
|
||||
var userFlagAssignemnt = (UserFlagAssignment)Event.Entity;
|
||||
|
||||
switch (Event.EventType)
|
||||
{
|
||||
case RepositoryMonitorEventType.Added:
|
||||
if (!userFlagAssignemnt.RemovedDate.HasValue)
|
||||
AddMember(userFlagAssignemnt.UserId);
|
||||
break;
|
||||
case RepositoryMonitorEventType.Modified:
|
||||
if (userFlagAssignemnt.RemovedDate.HasValue)
|
||||
RemoveMember(userFlagAssignemnt.UserId);
|
||||
else
|
||||
AddMember(userFlagAssignemnt.UserId);
|
||||
break;
|
||||
case RepositoryMonitorEventType.Deleted:
|
||||
string userId = userFlagAssignemnt.UserId;
|
||||
// Remove the user if no other (non-removed) assignments exist.
|
||||
RemoveMember(userId, (database) =>
|
||||
{
|
||||
if (database.UserFlagAssignments.Any(a => a.UserFlagId == UserFlagId && a.UserId == userId && !a.RemovedDate.HasValue))
|
||||
return null;
|
||||
else
|
||||
return new string[] { userId };
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
if (repositorySubscription != null)
|
||||
repositorySubscription.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ namespace Disco.Services.Users.UserFlags
|
||||
|
||||
// Parse Users
|
||||
var userIds = UserIds
|
||||
.Select(u => u.Contains('\\') ? u : string.Concat(ActiveDirectory.Context.PrimaryDomain.NetBiosName, @"\", u))
|
||||
.Select(u => ActiveDirectory.ParseDomainAccountId(u))
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase).ToList();
|
||||
|
||||
Status.UpdateStatus(10, "Loading users from the database");
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
{
|
||||
if (UserId != null)
|
||||
{
|
||||
@prepend <span>@Disco.Services.UserExtensions.FriendlyUserId(UserId)</span>
|
||||
@prepend <span>@Disco.Services.Interop.ActiveDirectory.ActiveDirectory.FriendlyAccountId(UserId)</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -674,7 +674,7 @@ WriteLiteralTo(@__razor_helper_writer, " <span>");
|
||||
|
||||
|
||||
#line 58 "..\..\App_Code\CommonHelpers.cshtml"
|
||||
WriteTo(@__razor_helper_writer, Disco.Services.UserExtensions.FriendlyUserId(UserId));
|
||||
WriteTo(@__razor_helper_writer, Disco.Services.Interop.ActiveDirectory.ActiveDirectory.FriendlyAccountId(UserId));
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
@@ -59,6 +59,10 @@ namespace Disco.Web
|
||||
// Initialize User Flags
|
||||
Disco.Services.Users.UserFlags.UserFlagService.Initialize(Database);
|
||||
|
||||
// Initialize Satellite Managed Groups (which don't belong to any other component)
|
||||
Disco.Services.Devices.ManagedGroups.DeviceManagedGroups.Initialize(Database);
|
||||
Disco.BI.DocumentTemplateBI.ManagedGroups.DocumentTemplateManagedGroups.Initialize(Database);
|
||||
|
||||
// Initialize Plugins
|
||||
Disco.Services.Plugins.Plugins.InitalizePlugins(Database);
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web.Extensions;
|
||||
using System;
|
||||
@@ -27,6 +30,8 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
const string pInsuredUntil = "insureduntil";
|
||||
const string pInsuranceDetails = "insurancedetails";
|
||||
const string pComments = "comments";
|
||||
const string pDevicesLinkedGroup = "deviceslinkedgroup";
|
||||
const string pAssignedUsersLinkedGroup = "assigneduserslinkedgroup";
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DeviceBatch.Configure)]
|
||||
public virtual ActionResult Update(int id, string key, string value = null, bool redirect = false)
|
||||
@@ -86,6 +91,12 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
case pComments:
|
||||
UpdateComments(deviceBatch, value);
|
||||
break;
|
||||
case pDevicesLinkedGroup:
|
||||
UpdateDevicesLinkedGroup(deviceBatch, value);
|
||||
break;
|
||||
case pAssignedUsersLinkedGroup:
|
||||
UpdateAssignedUsersLinkedGroup(deviceBatch, value);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid Update Key");
|
||||
}
|
||||
@@ -193,6 +204,71 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
return Update(id, pComments, Comments, redirect);
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DeviceBatch.Configure)]
|
||||
public virtual ActionResult UpdateDevicesLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var deviceBatch = Database.DeviceBatches.Find(id);
|
||||
if (deviceBatch == null)
|
||||
throw new ArgumentException("Invalid Device Batch Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateDevicesLinkedGroup(deviceBatch, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DeviceBatch.Index(deviceBatch.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DeviceBatch.Index(deviceBatch.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
[DiscoAuthorize(Claims.Config.DeviceBatch.Configure)]
|
||||
public virtual ActionResult UpdateAssignedUsersLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var deviceBatch = Database.DeviceBatches.Find(id);
|
||||
if (deviceBatch == null)
|
||||
throw new ArgumentException("Invalid Device Batch Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateAssignedUsersLinkedGroup(deviceBatch, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DeviceBatch.Index(deviceBatch.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DeviceBatch.Index(deviceBatch.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Update Properties
|
||||
@@ -397,6 +473,40 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
deviceBatch.Comments = Comments;
|
||||
Database.SaveChanges();
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateDevicesLinkedGroup(DeviceBatch DeviceBatch, string DevicesLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DeviceBatchDevicesManagedGroup.GetKey(DeviceBatch), DevicesLinkedGroup, null);
|
||||
|
||||
if (DeviceBatch.DevicesLinkedGroup != configJson)
|
||||
{
|
||||
DeviceBatch.DevicesLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DeviceBatchDevicesManagedGroup.Initialize(DeviceBatch);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateAssignedUsersLinkedGroup(DeviceBatch DeviceBatch, string AssignedUsersLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DeviceBatchAssignedUsersManagedGroup.GetKey(DeviceBatch), AssignedUsersLinkedGroup, null);
|
||||
|
||||
if (DeviceBatch.AssignedUsersLinkedGroup != configJson)
|
||||
{
|
||||
DeviceBatch.AssignedUsersLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DeviceBatchDevicesManagedGroup.Initialize(DeviceBatch);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
@@ -131,15 +131,10 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Device.Actions.AssignUser)]
|
||||
public virtual ActionResult UpdateAssignedUserId(string id, string AssignedUserId = null, string AssignedUserDomain = null, bool redirect = false)
|
||||
public virtual ActionResult UpdateAssignedUserId(string id, string AssignedUserId = null, bool redirect = false)
|
||||
{
|
||||
if (AssignedUserId != null && !AssignedUserId.Contains('\\'))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(AssignedUserDomain))
|
||||
AssignedUserId = string.Format(@"{0}\{1}", ActiveDirectory.Context.PrimaryDomain.NetBiosName, AssignedUserId);
|
||||
else
|
||||
AssignedUserId = string.Format(@"{0}\{1}", AssignedUserDomain, AssignedUserId);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(AssignedUserId))
|
||||
AssignedUserId = ActiveDirectory.ParseDomainAccountId(AssignedUserId);
|
||||
|
||||
return Update(id, pAssignedUserId, AssignedUserId, redirect);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.Services.Web;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
public partial class DeviceProfileController : AuthorizedDatabaseController
|
||||
{
|
||||
|
||||
const string pDescription = "description";
|
||||
const string pName = "name";
|
||||
const string pShortName = "shortname";
|
||||
@@ -25,6 +25,8 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
const string pProvisionADAccount = "provisionadaccount";
|
||||
const string pAssignedUserLocalAdmin = "assigneduserlocaladmin";
|
||||
const string pAllowUntrustedReimageJobEnrolment = "allowuntrustedreimagejobrnrolment";
|
||||
const string pDevicesLinkedGroup = "deviceslinkedgroup";
|
||||
const string pAssignedUsersLinkedGroup = "assigneduserslinkedgroup";
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DeviceProfile.Configure)]
|
||||
public virtual ActionResult Update(int id, string key, string value = null, Nullable<bool> redirect = null)
|
||||
@@ -82,6 +84,12 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
case pAllowUntrustedReimageJobEnrolment:
|
||||
UpdateAllowUntrustedReimageJobEnrolment(deviceProfile, value);
|
||||
break;
|
||||
case pDevicesLinkedGroup:
|
||||
UpdateDevicesLinkedGroup(deviceProfile, value);
|
||||
break;
|
||||
case pAssignedUsersLinkedGroup:
|
||||
UpdateAssignedUsersLinkedGroup(deviceProfile, value);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid Update Key");
|
||||
}
|
||||
@@ -183,6 +191,71 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
{
|
||||
return Update(id, pAllowUntrustedReimageJobEnrolment, AllowUntrustedReimageJobEnrolment, redirect);
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DeviceProfile.Configure)]
|
||||
public virtual ActionResult UpdateDevicesLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var deviceProfile = Database.DeviceProfiles.Find(id);
|
||||
if (deviceProfile == null)
|
||||
throw new ArgumentException("Invalid Device Profile Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateDevicesLinkedGroup(deviceProfile, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DeviceProfile.Index(deviceProfile.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DeviceProfile.Index(deviceProfile.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
[DiscoAuthorize(Claims.Config.DeviceProfile.Configure)]
|
||||
public virtual ActionResult UpdateAssignedUsersLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var deviceProfile = Database.DeviceProfiles.Find(id);
|
||||
if (deviceProfile == null)
|
||||
throw new ArgumentException("Invalid Device Profile Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateAssignedUsersLinkedGroup(deviceProfile, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DeviceProfile.Index(deviceProfile.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DeviceProfile.Index(deviceProfile.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Update Properties
|
||||
@@ -365,6 +438,40 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
throw new Exception("Invalid Boolean Value");
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateDevicesLinkedGroup(DeviceProfile DeviceProfile, string DevicesLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DeviceProfileDevicesManagedGroup.GetKey(DeviceProfile), DevicesLinkedGroup, null);
|
||||
|
||||
if (DeviceProfile.DevicesLinkedGroup != configJson)
|
||||
{
|
||||
DeviceProfile.DevicesLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DeviceProfileDevicesManagedGroup.Initialize(DeviceProfile);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateAssignedUsersLinkedGroup(DeviceProfile DeviceProfile, string AssignedUsersLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DeviceProfileAssignedUsersManagedGroup.GetKey(DeviceProfile), AssignedUsersLinkedGroup, null);
|
||||
|
||||
if (DeviceProfile.AssignedUsersLinkedGroup != configJson)
|
||||
{
|
||||
DeviceProfile.AssignedUsersLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DeviceProfileAssignedUsersManagedGroup.Initialize(DeviceProfile);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using Disco.BI;
|
||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.Services.Users;
|
||||
using Disco.Services.Web;
|
||||
using System;
|
||||
@@ -30,7 +32,10 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
throw new ArgumentNullException("id");
|
||||
if (string.IsNullOrEmpty(key))
|
||||
throw new ArgumentNullException("key");
|
||||
|
||||
ScheduledTaskStatus resultTask = null;
|
||||
var documentTemplate = Database.DocumentTemplates.Find(id);
|
||||
|
||||
if (documentTemplate != null)
|
||||
{
|
||||
switch (key.ToLower())
|
||||
@@ -39,7 +44,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
UpdateDescription(documentTemplate, value);
|
||||
break;
|
||||
case pScope:
|
||||
UpdateScope(documentTemplate, value);
|
||||
resultTask = UpdateScope(documentTemplate, value);
|
||||
break;
|
||||
case pFilterExpression:
|
||||
Authorization.Require(Claims.Config.DocumentTemplate.ConfigureFilterExpression);
|
||||
@@ -57,7 +62,15 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
throw new Exception("Invalid Document Template Id");
|
||||
}
|
||||
if (redirect)
|
||||
return RedirectToAction(MVC.Config.DocumentTemplate.Index(documentTemplate.Id));
|
||||
if (resultTask == null)
|
||||
{
|
||||
return RedirectToAction(MVC.Config.DocumentTemplate.Index(documentTemplate.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
resultTask.SetFinishedUrl(Url.Action(MVC.Config.DocumentTemplate.Index(documentTemplate.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(resultTask.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
@@ -163,6 +176,72 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DocumentTemplate.Configure)]
|
||||
public virtual ActionResult UpdateDevicesLinkedGroup(string id, string GroupId = null, DateTime? FilterBeginDate = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentNullException("id");
|
||||
|
||||
var documentTemplate = Database.DocumentTemplates.Find(id);
|
||||
if (documentTemplate == null)
|
||||
throw new ArgumentException("Invalid Document Template Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateDevicesLinkedGroup(documentTemplate, GroupId, FilterBeginDate);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DocumentTemplate.Index(documentTemplate.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DocumentTemplate.Index(documentTemplate.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
|
||||
[DiscoAuthorize(Claims.Config.DocumentTemplate.Configure)]
|
||||
public virtual ActionResult UpdateUsersLinkedGroup(string id, string GroupId = null, DateTime? FilterBeginDate = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(id))
|
||||
throw new ArgumentNullException("id");
|
||||
|
||||
var documentTemplate = Database.DocumentTemplates.Find(id);
|
||||
if (documentTemplate == null)
|
||||
throw new ArgumentException("Invalid Document Template Id", "id");
|
||||
|
||||
var syncTaskStatus = UpdateUsersLinkedGroup(documentTemplate, GroupId, FilterBeginDate);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.DocumentTemplate.Index(documentTemplate.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.DocumentTemplate.Index(documentTemplate.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Update Properties
|
||||
@@ -176,28 +255,38 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
throw new Exception("Invalid Description");
|
||||
}
|
||||
private void UpdateScope(Disco.Models.Repository.DocumentTemplate documentTemplate, string Scope)
|
||||
private ScheduledTaskStatus UpdateScope(Disco.Models.Repository.DocumentTemplate documentTemplate, string Scope)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Scope))
|
||||
if (string.IsNullOrWhiteSpace(Scope) || !Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.ToList().Contains(Scope))
|
||||
throw new ArgumentException("Invalid Scope", "Scope");
|
||||
|
||||
Database.Configuration.LazyLoadingEnabled = true;
|
||||
|
||||
if (documentTemplate.Scope != Scope)
|
||||
{
|
||||
if (Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.ToList().Contains(Scope))
|
||||
|
||||
documentTemplate.Scope = Scope;
|
||||
|
||||
if (documentTemplate.Scope != Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.Job &&
|
||||
documentTemplate.JobSubTypes != null)
|
||||
{
|
||||
Database.Configuration.LazyLoadingEnabled = true;
|
||||
|
||||
documentTemplate.Scope = Scope;
|
||||
|
||||
if (documentTemplate.Scope != Disco.Models.Repository.DocumentTemplate.DocumentTemplateScopes.Job &&
|
||||
documentTemplate.JobSubTypes != null)
|
||||
{
|
||||
foreach (var st in documentTemplate.JobSubTypes.ToArray())
|
||||
documentTemplate.JobSubTypes.Remove(st);
|
||||
}
|
||||
|
||||
Database.SaveChanges();
|
||||
return;
|
||||
foreach (var st in documentTemplate.JobSubTypes.ToArray())
|
||||
documentTemplate.JobSubTypes.Remove(st);
|
||||
}
|
||||
|
||||
Database.SaveChanges();
|
||||
|
||||
// Trigger Managed Group Sync
|
||||
var managedGroups = new ADManagedGroup[] {
|
||||
DocumentTemplateDevicesManagedGroup.Initialize(documentTemplate),
|
||||
DocumentTemplateUsersManagedGroup.Initialize(documentTemplate)
|
||||
};
|
||||
|
||||
if (managedGroups.Any(mg => mg != null)) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroups.Where(mg => mg != null));
|
||||
}
|
||||
throw new Exception("Invalid Scope");
|
||||
|
||||
return null;
|
||||
}
|
||||
private void UpdateFilterExpression(Disco.Models.Repository.DocumentTemplate documentTemplate, string FilterExpression)
|
||||
{
|
||||
@@ -257,6 +346,40 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
Database.SaveChanges();
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateDevicesLinkedGroup(DocumentTemplate DocumentTemplate, string DevicesLinkedGroup, DateTime? FilterBeginDate)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DocumentTemplateDevicesManagedGroup.GetKey(DocumentTemplate), DevicesLinkedGroup, FilterBeginDate);
|
||||
|
||||
if (DocumentTemplate.DevicesLinkedGroup != configJson)
|
||||
{
|
||||
DocumentTemplate.DevicesLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DocumentTemplateDevicesManagedGroup.Initialize(DocumentTemplate);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateUsersLinkedGroup(DocumentTemplate DocumentTemplate, string UsersLinkedGroup, DateTime? FilterBeginDate)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(DocumentTemplateUsersManagedGroup.GetKey(DocumentTemplate), UsersLinkedGroup, FilterBeginDate);
|
||||
|
||||
if (DocumentTemplate.UsersLinkedGroup != configJson)
|
||||
{
|
||||
DocumentTemplate.UsersLinkedGroup = configJson;
|
||||
Database.SaveChanges();
|
||||
|
||||
var managedGroup = DocumentTemplateUsersManagedGroup.Initialize(DocumentTemplate);
|
||||
if (managedGroup != null) // Sync Group
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Actions
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.Config.System.Show)]
|
||||
public virtual ActionResult UpdateLastNetworkLogonDates()
|
||||
{
|
||||
var taskStatus = Disco.Services.Interop.ActiveDirectory.ADTaskUpdateNetworkLogonDates.ScheduleImmediately();
|
||||
var taskStatus = Disco.Services.Interop.ActiveDirectory.ADNetworkLogonDatesUpdateTask.ScheduleImmediately();
|
||||
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
|
||||
}
|
||||
@@ -294,6 +294,17 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[DiscoAuthorizeAny(Claims.Config.UserFlag.Configure)]
|
||||
public virtual ActionResult SearchGroupSubjects(string term)
|
||||
{
|
||||
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
|
||||
|
||||
var results = groupResults.OrderBy(r => r.SamAccountName)
|
||||
.Select(r => Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
|
||||
|
||||
return Json(results, JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
|
||||
public virtual ActionResult Subject(string Id)
|
||||
{
|
||||
@@ -305,6 +316,22 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return Json(Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
|
||||
[DiscoAuthorizeAny(Claims.Config.UserFlag.Configure)]
|
||||
public virtual ActionResult SyncActiveDirectoryManagedGroup(string id, string redirectUrl = null)
|
||||
{
|
||||
ADManagedGroup managedGroup;
|
||||
|
||||
if (!ActiveDirectory.Context.ManagedGroups.TryGetValue(id, out managedGroup))
|
||||
throw new ArgumentException("Unknown Managed Group Key");
|
||||
|
||||
var taskStatus = ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
|
||||
if (redirectUrl != null)
|
||||
taskStatus.SetFinishedUrl(redirectUrl);
|
||||
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(taskStatus.SessionId));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Proxy Settings
|
||||
|
||||
@@ -58,10 +58,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.User.Actions.AddAttachments)]
|
||||
public virtual ActionResult AttachmentUpload(string id, string Domain, string Comments)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
id = ActiveDirectory.ParseDomainAccountId(id, Domain);
|
||||
|
||||
var u = Database.Users.Find(id);
|
||||
if (u != null)
|
||||
@@ -120,10 +117,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
[DiscoAuthorize(Claims.User.ShowAttachments)]
|
||||
public virtual ActionResult Attachments(string id, string Domain)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
id = ActiveDirectory.ParseDomainAccountId(id, Domain);
|
||||
|
||||
var u = Database.Users.Include("UserAttachments.DocumentTemplate").Include("UserAttachments.TechUser").Where(m => m.UserId == id).FirstOrDefault();
|
||||
if (u != null)
|
||||
@@ -167,10 +161,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
if (string.IsNullOrEmpty(DocumentTemplateId))
|
||||
throw new ArgumentNullException("AttachmentTypeId");
|
||||
|
||||
if (string.IsNullOrEmpty(Domain))
|
||||
id = ActiveDirectory.Context.PrimaryDomain.NetBiosName + @"\" + id;
|
||||
else
|
||||
id = Domain + @"\" + id;
|
||||
id = ActiveDirectory.ParseDomainAccountId(id, Domain);
|
||||
|
||||
var user = Database.Users.Find(id);
|
||||
if (user != null)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Tasks;
|
||||
using Disco.Services.Users.UserFlags;
|
||||
using Disco.Services.Web;
|
||||
@@ -15,6 +17,8 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
const string pDescription = "description";
|
||||
const string pIcon = "icon";
|
||||
const string pIconColour = "iconcolour";
|
||||
const string pAssignedUsersLinkedGroup = "assigneduserslinkedgroup";
|
||||
const string pAssignedUserDevicesLinkedGroup = "assigneduserdeviceslinkedgroup";
|
||||
|
||||
[DiscoAuthorize(Claims.Config.UserFlag.Configure)]
|
||||
public virtual ActionResult Update(int id, string key, string value = null, Nullable<bool> redirect = null)
|
||||
@@ -44,6 +48,12 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
case pIconColour:
|
||||
UpdateIconColour(flag, value);
|
||||
break;
|
||||
case pAssignedUsersLinkedGroup:
|
||||
UpdateAssignedUsersLinkedGroup(flag, value);
|
||||
break;
|
||||
case pAssignedUserDevicesLinkedGroup:
|
||||
UpdateAssignedUserDevicesLinkedGroup(flag, value);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid Update Key");
|
||||
}
|
||||
@@ -106,7 +116,7 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
}
|
||||
else
|
||||
{
|
||||
return Json("Invalid User Flag Id", JsonRequestBehavior.AllowGet);
|
||||
throw new ArgumentException("Invalid User Flag Id", "id");
|
||||
}
|
||||
if (redirect)
|
||||
return RedirectToAction(MVC.Config.UserFlag.Index(UserFlag.Id));
|
||||
@@ -121,6 +131,72 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
[DiscoAuthorize(Claims.Config.UserFlag.Configure)]
|
||||
public virtual ActionResult UpdateAssignedUsersLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var UserFlag = Database.UserFlags.Find(id);
|
||||
if (UserFlag == null)
|
||||
throw new ArgumentException("Invalid User Flag Id", "id");
|
||||
|
||||
|
||||
var syncTaskStatus = UpdateAssignedUsersLinkedGroup(UserFlag, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.UserFlag.Index(UserFlag.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.UserFlag.Index(UserFlag.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
[DiscoAuthorize(Claims.Config.UserFlag.Configure)]
|
||||
public virtual ActionResult UpdateAssignedUserDevicesLinkedGroup(int id, string GroupId = null, bool redirect = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (id < 0)
|
||||
throw new ArgumentOutOfRangeException("id");
|
||||
|
||||
var UserFlag = Database.UserFlags.Find(id);
|
||||
if (UserFlag == null)
|
||||
throw new ArgumentException("Invalid User Flag Id", "id");
|
||||
|
||||
|
||||
var syncTaskStatus = UpdateAssignedUserDevicesLinkedGroup(UserFlag, GroupId);
|
||||
if (redirect)
|
||||
if (syncTaskStatus == null)
|
||||
return RedirectToAction(MVC.Config.UserFlag.Index(UserFlag.Id));
|
||||
else
|
||||
{
|
||||
syncTaskStatus.SetFinishedUrl(Url.Action(MVC.Config.UserFlag.Index(UserFlag.Id)));
|
||||
return RedirectToAction(MVC.Config.Logging.TaskStatus(syncTaskStatus.SessionId));
|
||||
}
|
||||
else
|
||||
return Json("OK", JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (redirect)
|
||||
throw;
|
||||
else
|
||||
return Json(string.Format("Error: {0}", ex.Message), JsonRequestBehavior.AllowGet);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Update Properties
|
||||
@@ -131,37 +207,98 @@ namespace Disco.Web.Areas.API.Controllers
|
||||
if (string.IsNullOrWhiteSpace(IconColour))
|
||||
throw new ArgumentNullException("IconColour");
|
||||
|
||||
UserFlag.Icon = Icon;
|
||||
UserFlag.IconColour = IconColour;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
if (UserFlag.Icon != Icon ||
|
||||
UserFlag.IconColour != IconColour)
|
||||
{
|
||||
UserFlag.Icon = Icon;
|
||||
UserFlag.IconColour = IconColour;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
}
|
||||
}
|
||||
private void UpdateIcon(UserFlag UserFlag, string Icon)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Icon))
|
||||
throw new ArgumentNullException("Icon");
|
||||
|
||||
UserFlag.Icon = Icon;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
if (UserFlag.Icon != Icon)
|
||||
{
|
||||
UserFlag.Icon = Icon;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
}
|
||||
}
|
||||
private void UpdateIconColour(UserFlag UserFlag, string IconColour)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(IconColour))
|
||||
throw new ArgumentNullException("IconColour");
|
||||
|
||||
UserFlag.IconColour = IconColour;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
if (UserFlag.IconColour != IconColour)
|
||||
{
|
||||
UserFlag.IconColour = IconColour;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateName(UserFlag UserFlag, string Name)
|
||||
{
|
||||
UserFlag.Name = Name;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
if (UserFlag.Name != Name)
|
||||
{
|
||||
UserFlag.Name = Name;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDescription(UserFlag UserFlag, string Description)
|
||||
{
|
||||
UserFlag.Description = Description;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
if (UserFlag.Description != Description)
|
||||
{
|
||||
UserFlag.Description = Description;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
}
|
||||
}
|
||||
|
||||
private ScheduledTaskStatus UpdateAssignedUsersLinkedGroup(UserFlag UserFlag, string AssignedUsersLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(UserFlagUsersManagedGroup.GetKey(UserFlag), AssignedUsersLinkedGroup, null);
|
||||
|
||||
if (UserFlag.UsersLinkedGroup != configJson)
|
||||
{
|
||||
UserFlag.UsersLinkedGroup = configJson;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
|
||||
if (UserFlag.UsersLinkedGroup != null)
|
||||
{
|
||||
// Sync Group
|
||||
UserFlagUsersManagedGroup managedGroup;
|
||||
if (UserFlagUsersManagedGroup.TryGetManagedGroup(UserFlag, out managedGroup))
|
||||
{
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private ScheduledTaskStatus UpdateAssignedUserDevicesLinkedGroup(UserFlag UserFlag, string AssignedUserDevicesLinkedGroup)
|
||||
{
|
||||
var configJson = ADManagedGroup.ValidConfigurationToJson(UserFlagUserDevicesManagedGroup.GetKey(UserFlag), AssignedUserDevicesLinkedGroup, null);
|
||||
|
||||
if (UserFlag.UserDevicesLinkedGroup != configJson)
|
||||
{
|
||||
UserFlag.UserDevicesLinkedGroup = configJson;
|
||||
UserFlagService.Update(Database, UserFlag);
|
||||
|
||||
if (UserFlag.UserDevicesLinkedGroup != null)
|
||||
{
|
||||
// Sync Group
|
||||
UserFlagUserDevicesManagedGroup managedGroup;
|
||||
if (UserFlagUserDevicesManagedGroup.TryGetManagedGroup(UserFlag, out managedGroup))
|
||||
{
|
||||
return ADManagedGroupsSyncTask.ScheduleSync(managedGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.UI.Config.DeviceBatch;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using Disco.Services.Plugins.Features.UIExtension;
|
||||
using Disco.Services.Web;
|
||||
using System;
|
||||
@@ -36,6 +37,13 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
DeviceDecommissionedCount = dG.Count(d => d.DecommissionedDate.HasValue)
|
||||
}).ToArray().Cast<ConfigDeviceBatchShowModelMembership>().ToList();
|
||||
|
||||
DeviceBatchAssignedUsersManagedGroup assignedUsersManagedGroup;
|
||||
if (DeviceBatchAssignedUsersManagedGroup.TryGetManagedGroup(m.DeviceBatch, out assignedUsersManagedGroup))
|
||||
m.AssignedUsersLinkedGroup = assignedUsersManagedGroup;
|
||||
DeviceBatchDevicesManagedGroup devicesManagedGroup;
|
||||
if (DeviceBatchDevicesManagedGroup.TryGetManagedGroup(m.DeviceBatch, out devicesManagedGroup))
|
||||
m.DevicesLinkedGroup = devicesManagedGroup;
|
||||
|
||||
if (Authorization.Has(Claims.Config.DeviceBatch.Delete))
|
||||
m.CanDelete = m.DeviceBatch.CanDelete(Database);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.UI.Config.DeviceProfile;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Plugins;
|
||||
using Disco.Services.Plugins.Features.CertificateProvider;
|
||||
@@ -36,6 +37,13 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
if (m.DeviceProfile.DefaultOrganisationAddress.HasValue)
|
||||
m.DefaultOrganisationAddress = Database.DiscoConfiguration.OrganisationAddresses.GetAddress(m.DeviceProfile.DefaultOrganisationAddress.Value);
|
||||
|
||||
DeviceProfileAssignedUsersManagedGroup assignedUsersManagedGroup;
|
||||
if (DeviceProfileAssignedUsersManagedGroup.TryGetManagedGroup(m.DeviceProfile, out assignedUsersManagedGroup))
|
||||
m.AssignedUsersLinkedGroup = assignedUsersManagedGroup;
|
||||
DeviceProfileDevicesManagedGroup devicesManagedGroup;
|
||||
if (DeviceProfileDevicesManagedGroup.TryGetManagedGroup(m.DeviceProfile, out devicesManagedGroup))
|
||||
m.DevicesLinkedGroup = devicesManagedGroup;
|
||||
|
||||
m.CertificateProviders = Plugins.GetPluginFeatures(typeof(CertificateProviderFeature));
|
||||
|
||||
var DistributionValues = Enum.GetValues(typeof(Disco.Models.Repository.DeviceProfile.DistributionTypes));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.UI.Config.DocumentTemplate;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Plugins.Features.UIExtension;
|
||||
@@ -33,6 +34,13 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
m.TemplateExpressions = m.DocumentTemplate.ExtractPdfExpressions(Database);
|
||||
m.UpdateModel(Database);
|
||||
|
||||
DocumentTemplateDevicesManagedGroup devicesManagedGroup;
|
||||
if (DocumentTemplateDevicesManagedGroup.TryGetManagedGroup(m.DocumentTemplate, out devicesManagedGroup))
|
||||
m.DevicesLinkedGroup = devicesManagedGroup;
|
||||
DocumentTemplateUsersManagedGroup usersManagedGroup;
|
||||
if (DocumentTemplateUsersManagedGroup.TryGetManagedGroup(m.DocumentTemplate, out usersManagedGroup))
|
||||
m.UsersLinkedGroup = usersManagedGroup;
|
||||
|
||||
// UI Extensions
|
||||
UIExtensions.ExecuteExtensions<ConfigDocumentTemplateShowModel>(this.ControllerContext, m);
|
||||
|
||||
|
||||
@@ -30,6 +30,13 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
if (m == null)
|
||||
throw new ArgumentException("Invalid User Flag Id");
|
||||
|
||||
UserFlagUsersManagedGroup assignedUsersManagedGroup;
|
||||
if (UserFlagUsersManagedGroup.TryGetManagedGroup(m.UserFlag, out assignedUsersManagedGroup))
|
||||
m.UsersLinkedGroup = assignedUsersManagedGroup;
|
||||
UserFlagUserDevicesManagedGroup assignedUserDevicesManagedGroup;
|
||||
if (UserFlagUserDevicesManagedGroup.TryGetManagedGroup(m.UserFlag, out assignedUserDevicesManagedGroup))
|
||||
m.UserDevicesLinkedGroup = assignedUserDevicesManagedGroup;
|
||||
|
||||
if (Authorization.Has(Claims.Config.UserFlag.Configure))
|
||||
{
|
||||
m.Icons = UIHelpers.Icons;
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
using Disco.Models.UI.Config.DeviceBatch;
|
||||
using System;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.DeviceBatch
|
||||
{
|
||||
public class ShowModel : ConfigDeviceBatchShowModel
|
||||
{
|
||||
public Disco.Models.Repository.DeviceBatch DeviceBatch { get; set; }
|
||||
|
||||
public Disco.Models.Repository.DeviceModel DefaultDeviceModel { get; set; }
|
||||
|
||||
public List<Disco.Models.Repository.DeviceModel> DeviceModels { get; set; }
|
||||
public List<ConfigDeviceBatchShowModelMembership> DeviceModelMembers { get; set; }
|
||||
|
||||
public DeviceBatchAssignedUsersManagedGroup AssignedUsersLinkedGroup { get; set; }
|
||||
public DeviceBatchDevicesManagedGroup DevicesLinkedGroup { get; set; }
|
||||
|
||||
public int DeviceCount { get; set; }
|
||||
public int DeviceDecommissionedCount { get; set; }
|
||||
public bool CanDelete { get; set; }
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Disco.Services.Plugins;
|
||||
using Disco.Models.UI.Config.DeviceProfile;
|
||||
using Disco.Models.UI.Config.DeviceProfile;
|
||||
using Disco.Services.Devices.ManagedGroups;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Plugins;
|
||||
using System.Collections.Generic;
|
||||
using System.Web.Mvc;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.DeviceProfile
|
||||
{
|
||||
@@ -16,6 +14,9 @@ namespace Disco.Web.Areas.Config.Models.DeviceProfile
|
||||
public Disco.Models.BI.Config.OrganisationAddress DefaultOrganisationAddress { get; set; }
|
||||
public List<Disco.Models.BI.Config.OrganisationAddress> OrganisationAddresses { get; set; }
|
||||
|
||||
public DeviceProfileAssignedUsersManagedGroup AssignedUsersLinkedGroup { get; set; }
|
||||
public DeviceProfileDevicesManagedGroup DevicesLinkedGroup { get; set; }
|
||||
|
||||
public string FriendlyOrganisationalUnitName
|
||||
{
|
||||
get
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Web;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.UI.Config.DocumentTemplate;
|
||||
using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.DocumentTemplate
|
||||
{
|
||||
@@ -26,6 +27,9 @@ namespace Disco.Web.Areas.Config.Models.DocumentTemplate
|
||||
}
|
||||
}
|
||||
|
||||
public DocumentTemplateDevicesManagedGroup DevicesLinkedGroup { get; set; }
|
||||
public DocumentTemplateUsersManagedGroup UsersLinkedGroup { get; set; }
|
||||
|
||||
public void UpdateModel(DiscoDataContext Database)
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.Shared
|
||||
{
|
||||
public class LinkedGroupModel
|
||||
{
|
||||
public bool CanConfigure { get; set; }
|
||||
|
||||
public string Description { get; set; }
|
||||
public string CategoryDescription { get; set; }
|
||||
|
||||
public string UpdateUrl { get; set; }
|
||||
|
||||
public ADManagedGroup ManagedGroup { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Models.UI.Config.UserFlag;
|
||||
using Disco.Services.Users.UserFlags;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Disco.Web.Areas.Config.Models.UserFlag
|
||||
@@ -10,6 +11,9 @@ namespace Disco.Web.Areas.Config.Models.UserFlag
|
||||
public int CurrentAssignmentCount { get; set; }
|
||||
public int TotalAssignmentCount { get; set; }
|
||||
|
||||
public UserFlagUsersManagedGroup UsersLinkedGroup { get; set; }
|
||||
public UserFlagUserDevicesManagedGroup UserDevicesLinkedGroup { get; set; }
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Icons { get; set; }
|
||||
public IEnumerable<KeyValuePair<string, string>> ThemeColours { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
@model Disco.Web.Areas.Config.Models.DeviceBatch.ShowModel
|
||||
@using Disco.Services.Devices.ManagedGroups;
|
||||
@using Disco.Web.Areas.Config.Models.Shared;
|
||||
@{
|
||||
Authorization.Require(Claims.Config.DeviceBatch.Show);
|
||||
|
||||
@@ -7,6 +9,10 @@
|
||||
var canConfig = Authorization.Has(Claims.Config.DeviceBatch.Configure);
|
||||
var canDeviceModelShow = Authorization.Has(Claims.Config.DeviceModel.Show);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.DeviceBatch.AssignedUsersLinkedGroup == null &&
|
||||
Model.DeviceBatch.DevicesLinkedGroup == null;
|
||||
|
||||
if (canConfig)
|
||||
{
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers");
|
||||
@@ -14,7 +20,7 @@
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/tinymce");
|
||||
}
|
||||
}
|
||||
<div class="form deviceBatches" style="width: 730px">
|
||||
<div class="form deviceBatches@(hideAdvanced ? " Config_HideAdvanced" : null)" style="width: 730px">
|
||||
<table>
|
||||
<tr>
|
||||
<th style="width: 150px">Id:
|
||||
@@ -652,6 +658,54 @@
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@if (hideAdvanced)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;">
|
||||
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
|
||||
<script>
|
||||
$(function () {
|
||||
$('#Config_HideAdvanced_Show').click(function () {
|
||||
var $this = $(this);
|
||||
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
||||
$this.closest('tr').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>Linked Groups:
|
||||
</th>
|
||||
<td>
|
||||
<div>
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DeviceBatchDevicesManagedGroup.GetCategoryDescription(Model.DeviceBatch),
|
||||
Description = DeviceBatchDevicesManagedGroup.GetDescription(Model.DeviceBatch),
|
||||
ManagedGroup = Model.DevicesLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DeviceBatch.UpdateDevicesLinkedGroup(Model.DeviceBatch.Id, redirect: true))
|
||||
})
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DeviceBatchAssignedUsersManagedGroup.GetCategoryDescription(Model.DeviceBatch),
|
||||
Description = DeviceBatchAssignedUsersManagedGroup.GetDescription(Model.DeviceBatch),
|
||||
ManagedGroup = Model.AssignedUsersLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DeviceBatch.UpdateAssignedUsersLinkedGroup(Model.DeviceBatch.Id, redirect: true))
|
||||
})
|
||||
@if (canConfig)
|
||||
{
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
|
||||
}
|
||||
</div>
|
||||
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
|
||||
<i class="fa fa-info-circle information"></i> Linked Active Directory Groups are automatically synchronized to include members currently associated with this Device Batch.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="actionBar">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,6 @@
|
||||
@model Disco.Web.Areas.Config.Models.DeviceProfile.ShowModel
|
||||
@using Disco.Services.Devices.ManagedGroups;
|
||||
@using Disco.Web.Areas.Config.Models.Shared;
|
||||
@{
|
||||
Authorization.Require(Claims.Config.DeviceProfile.Show);
|
||||
|
||||
@@ -8,13 +10,17 @@
|
||||
var canConfigExpression = Authorization.Has(Claims.Config.DeviceProfile.ConfigureComputerNameTemplate);
|
||||
var canDelete = (Authorization.Has(Claims.Config.DeviceProfile.Delete) && Model.CanDelete);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.DeviceProfile.AssignedUsersLinkedGroup == null &&
|
||||
Model.DeviceProfile.DevicesLinkedGroup == null;
|
||||
|
||||
if (canConfig)
|
||||
{
|
||||
Html.BundleDeferred("~/Style/Fancytree");
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-Fancytree");
|
||||
}
|
||||
}
|
||||
<div id="configurationDeviceProfileShow" class="form" style="width: 640px">
|
||||
<div id="configurationDeviceProfileShow" class="form@(hideAdvanced ? " Config_HideAdvanced" : null)" style="width: 640px">
|
||||
<table>
|
||||
<tr>
|
||||
<th style="width: 170px;">Id:
|
||||
@@ -689,6 +695,54 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@if (hideAdvanced)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;">
|
||||
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
|
||||
<script>
|
||||
$(function () {
|
||||
$('#Config_HideAdvanced_Show').click(function () {
|
||||
var $this = $(this);
|
||||
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
||||
$this.closest('tr').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>Linked Groups:
|
||||
</th>
|
||||
<td>
|
||||
<div>
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DeviceProfileDevicesManagedGroup.GetCategoryDescription(Model.DeviceProfile),
|
||||
Description = DeviceProfileDevicesManagedGroup.GetDescription(Model.DeviceProfile),
|
||||
ManagedGroup = Model.DevicesLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DeviceProfile.UpdateDevicesLinkedGroup(Model.DeviceProfile.Id, redirect: true))
|
||||
})
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DeviceProfileAssignedUsersManagedGroup.GetCategoryDescription(Model.DeviceProfile),
|
||||
Description = DeviceProfileAssignedUsersManagedGroup.GetDescription(Model.DeviceProfile),
|
||||
ManagedGroup = Model.AssignedUsersLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DeviceProfile.UpdateAssignedUsersLinkedGroup(Model.DeviceProfile.Id, redirect: true))
|
||||
})
|
||||
@if (canConfig)
|
||||
{
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
|
||||
}
|
||||
</div>
|
||||
<div style="padding: 0.7em 0.7em;" class="ui-state-highlight ui-corner-all">
|
||||
<i class="fa fa-info-circle information"></i> Linked Active Directory Groups are automatically synchronized to include members currently associated with this Device Profile.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@if (canDelete)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,24 +10,24 @@
|
||||
Expressions within Disco are based on the <a href="http://www.springframework.net/"
|
||||
target="_blank">Spring.NET Framework</a>. Please refer to the <a href="http://www.springframework.net/doc-latest/reference/html/expressions.html"
|
||||
target="_blank">Expression Evaluation</a> documentation.
|
||||
<h2>
|
||||
<h2 id="DeviceScope">
|
||||
Device Scope</h2>
|
||||
<div id="deviceScopeTree" class="expressionTree">
|
||||
</div>
|
||||
<h2>
|
||||
<h2 id="JobScope">
|
||||
Job Scope</h2>
|
||||
<div id="jobScopeTree" class="expressionTree">
|
||||
</div>
|
||||
<h2>
|
||||
<h2 id="UserScope">
|
||||
User Scope</h2>
|
||||
<div id="userScopeTree" class="expressionTree">
|
||||
</div>
|
||||
<h2>
|
||||
<h2 id="Variables">
|
||||
Variables
|
||||
</h2>
|
||||
<div id="variableScopeTree" class="expressionTree">
|
||||
</div>
|
||||
<h2>
|
||||
<h2 id="ExtensionLibraries">
|
||||
Extension Libraries</h2>
|
||||
<div id="extScopeTree" class="expressionTree">
|
||||
</div>
|
||||
|
||||
@@ -73,32 +73,51 @@ WriteLiteral(" href=\"http://www.springframework.net/doc-latest/reference/html/e
|
||||
|
||||
WriteLiteral("\r\n target=\"_blank\"");
|
||||
|
||||
WriteLiteral(">Expression Evaluation</a> documentation.\r\n <h2>\r\n Device Scope</h2>\r\n " +
|
||||
" <div");
|
||||
WriteLiteral(">Expression Evaluation</a> documentation.\r\n <h2");
|
||||
|
||||
WriteLiteral(" id=\"DeviceScope\"");
|
||||
|
||||
WriteLiteral(">\r\n Device Scope</h2>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"deviceScopeTree\"");
|
||||
|
||||
WriteLiteral(" class=\"expressionTree\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n <h2>\r\n Job Scope</h2>\r\n <div");
|
||||
WriteLiteral(">\r\n </div>\r\n <h2");
|
||||
|
||||
WriteLiteral(" id=\"JobScope\"");
|
||||
|
||||
WriteLiteral(">\r\n Job Scope</h2>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"jobScopeTree\"");
|
||||
|
||||
WriteLiteral(" class=\"expressionTree\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n <h2>\r\n User Scope</h2>\r\n <div");
|
||||
WriteLiteral(">\r\n </div>\r\n <h2");
|
||||
|
||||
WriteLiteral(" id=\"UserScope\"");
|
||||
|
||||
WriteLiteral(">\r\n User Scope</h2>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"userScopeTree\"");
|
||||
|
||||
WriteLiteral(" class=\"expressionTree\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n <h2>\r\n Variables\r\n </h2>\r\n <div");
|
||||
WriteLiteral(">\r\n </div>\r\n <h2");
|
||||
|
||||
WriteLiteral(" id=\"Variables\"");
|
||||
|
||||
WriteLiteral(">\r\n Variables\r\n </h2>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"variableScopeTree\"");
|
||||
|
||||
WriteLiteral(" class=\"expressionTree\"");
|
||||
|
||||
WriteLiteral(">\r\n </div>\r\n <h2>\r\n Extension Libraries</h2>\r\n <div");
|
||||
WriteLiteral(">\r\n </div>\r\n <h2");
|
||||
|
||||
WriteLiteral(" id=\"ExtensionLibraries\"");
|
||||
|
||||
WriteLiteral(">\r\n Extension Libraries</h2>\r\n <div");
|
||||
|
||||
WriteLiteral(" id=\"extScopeTree\"");
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
@model Disco.Web.Areas.Config.Models.DocumentTemplate.ShowModel
|
||||
@using Disco.BI.DocumentTemplateBI.ManagedGroups;
|
||||
@using Disco.Services.Interop.ActiveDirectory;
|
||||
@using Disco.Web.Areas.Config.Models.Shared;
|
||||
@{
|
||||
Authorization.Require(Claims.Config.DocumentTemplate.Show);
|
||||
|
||||
var canConfig = Authorization.Has(Claims.Config.DocumentTemplate.Configure);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.DocumentTemplate.UsersLinkedGroup == null &&
|
||||
Model.DocumentTemplate.DevicesLinkedGroup == null &&
|
||||
Model.DocumentTemplate.FilterExpression == null &&
|
||||
Model.TemplateExpressions.All(e => e.All(p => !p.ParseError));
|
||||
|
||||
#region Can Bulk Generate
|
||||
var canBulkGenerate = Authorization.Has(Claims.Config.DocumentTemplate.BulkGenerate);
|
||||
if (canBulkGenerate)
|
||||
@@ -28,243 +36,179 @@
|
||||
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Document Templates", MVC.Config.DocumentTemplate.Index(null), Model.DocumentTemplate.Description);
|
||||
}
|
||||
<div class="form" style="width: 650px">
|
||||
<table>
|
||||
<tr>
|
||||
<th>Id:
|
||||
</th>
|
||||
<td>@Html.DisplayFor(model => model.DocumentTemplate.Id)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Stored Instances:
|
||||
</th>
|
||||
<td>@Html.DisplayFor(model => model.StoredInstanceCount)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Description:
|
||||
</th>
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
@Html.TextBoxFor(model => model.DocumentTemplate.Description)
|
||||
@AjaxHelpers.AjaxSave()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $Description = $('#DocumentTemplate_Description');
|
||||
var $DescriptionAjaxSave = $Description.next('.ajaxSave');
|
||||
$Description
|
||||
.watermark('Description')
|
||||
.focus(function () { $Description.select() })
|
||||
.keydown(function (e) {
|
||||
$DescriptionAjaxSave.show();
|
||||
if (e.which == 13) {
|
||||
$(this).blur();
|
||||
}
|
||||
}).blur(function () {
|
||||
$DescriptionAjaxSave.hide();
|
||||
})
|
||||
.change(function () {
|
||||
$DescriptionAjaxSave.hide();
|
||||
var $ajaxLoading = $DescriptionAjaxSave.next('.ajaxLoading').show();
|
||||
var data = { Description: $Description.val() };
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.DocumentTemplate.UpdateDescription(Model.DocumentTemplate.Id))',
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d == 'OK') {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
} else {
|
||||
$ajaxLoading.hide();
|
||||
alert('Unable to update description: ' + d);
|
||||
<div id="Config_DocumentTemplates_Show" class="@(hideAdvanced ? "Config_HideAdvanced" : null)">
|
||||
<div class="form" style="width: 650px; margin: 10px auto 20px;">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Id:
|
||||
</th>
|
||||
<td>@Html.DisplayFor(model => model.DocumentTemplate.Id)
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Statistics:
|
||||
</th>
|
||||
<td>
|
||||
<strong>@Html.DisplayFor(model => model.StoredInstanceCount)</strong> Stored Instance@(Model.StoredInstanceCount == 1 ? null : "s")
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Description:
|
||||
</th>
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
@Html.TextBoxFor(model => model.DocumentTemplate.Description)
|
||||
@AjaxHelpers.AjaxSave()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $Description = $('#DocumentTemplate_Description');
|
||||
var $DescriptionAjaxSave = $Description.next('.ajaxSave');
|
||||
$Description
|
||||
.watermark('Description')
|
||||
.focus(function () { $Description.select() })
|
||||
.keydown(function (e) {
|
||||
$DescriptionAjaxSave.show();
|
||||
if (e.which == 13) {
|
||||
$(this).blur();
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to update description: ' + textStatus);
|
||||
$ajaxLoading.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(Model.DocumentTemplate.Description))
|
||||
{
|
||||
<span class="smallMessage"><None Specified></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.DocumentTemplate.Description
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Always Flatten Form:
|
||||
</th>
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
<input id="DocumentTemplate_FlattenForm" type="checkbox" @(Model.DocumentTemplate.FlattenForm ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty))/>
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#DocumentTemplate_FlattenForm').click(function () {
|
||||
var $this = $(this);
|
||||
var $ajaxLoading = $this.next('.ajaxLoading').show();
|
||||
var data = { FlattenForm: $this.is(':checked') };
|
||||
$.getJSON('@(Url.Action(MVC.API.DocumentTemplate.UpdateFlattenForm(Model.DocumentTemplate.Id)))', data, function (response, result) {
|
||||
if (result != 'success' || response != 'OK') {
|
||||
alert('Unable to change Flatten Form:\n' + response);
|
||||
$ajaxLoading.hide();
|
||||
} else {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="DocumentTemplate_FlattenForm" type="checkbox" @(Model.DocumentTemplate.FlattenForm ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)) disabled="disabled" />
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Scope:
|
||||
</th>
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
@Html.DropDownListFor(model => model.DocumentTemplate.Scope, Model.Scopes.ToSelectListItems(null))
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $scope = $('#DocumentTemplate_Scope');
|
||||
$scope.change(function () {
|
||||
var $ajaxLoading = $scope.next('.ajaxLoading').show();
|
||||
var data = { Scope: $scope.val() };
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.DocumentTemplate.UpdateScope(Model.DocumentTemplate.Id))',
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d == 'OK') {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
scopeChange();
|
||||
} else {
|
||||
$ajaxLoading.hide();
|
||||
alert('Unable to update scope: ' + d);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to update scope: ' + textStatus);
|
||||
$ajaxLoading.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var $JobSubTypes = $('#Config_DocumentTemplates_JobSubTypes');
|
||||
|
||||
function scopeChange() {
|
||||
if ($scope.val() == 'Job') {
|
||||
$JobSubTypes.slideDown('fast');
|
||||
} else {
|
||||
$JobSubTypes.slideUp('fast');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div>@Model.DocumentTemplate.Scope</div>
|
||||
}
|
||||
@if (canConfig || (Model.DocumentTemplate.Scope == DocumentTemplate.DocumentTemplateScopes.Job))
|
||||
{
|
||||
<div id="Config_DocumentTemplates_JobSubTypes" @(Model.DocumentTemplate.Scope != DocumentTemplate.DocumentTemplateScopes.Job ? "style=\"display: none;\" " : null)>
|
||||
<h4>Filter:</h4>
|
||||
<div>
|
||||
@if (Model.DocumentTemplate.JobSubTypes.Count > 0)
|
||||
{
|
||||
<ul>
|
||||
@foreach (var jobType in Model.DocumentTemplate.JobSubTypes.GroupBy(jst => jst.JobType).OrderBy(jtg => jtg.Key.Description))
|
||||
{
|
||||
<li>
|
||||
@jobType.Key.Description
|
||||
<ul>
|
||||
@if (jobType.Count() == Model.JobTypes.FirstOrDefault(jt => jt.Id == jobType.Key.Id).JobSubTypes.Count)
|
||||
{
|
||||
<li><span class="smallMessage">[All Sub Types]</span></li>
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var jobSubType in jobType)
|
||||
{
|
||||
<li>@jobSubType.Description</li>
|
||||
}).blur(function () {
|
||||
$DescriptionAjaxSave.hide();
|
||||
})
|
||||
.change(function () {
|
||||
$DescriptionAjaxSave.hide();
|
||||
var $ajaxLoading = $DescriptionAjaxSave.next('.ajaxLoading').show();
|
||||
var data = { Description: $Description.val() };
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.DocumentTemplate.UpdateDescription(Model.DocumentTemplate.Id))',
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d == 'OK') {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
} else {
|
||||
$ajaxLoading.hide();
|
||||
alert('Unable to update description: ' + d);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to update description: ' + textStatus);
|
||||
$ajaxLoading.hide();
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrEmpty(Model.DocumentTemplate.Description))
|
||||
{
|
||||
<span class="smallMessage"><None Specified></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span class="smallMessage"><No Filter></span>
|
||||
@Model.DocumentTemplate.Description
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Always Flatten Form:
|
||||
</th>
|
||||
<td>@if (canConfig)
|
||||
{
|
||||
<input id="DocumentTemplate_FlattenForm" type="checkbox" @(Model.DocumentTemplate.FlattenForm ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty))/>
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('#DocumentTemplate_FlattenForm').click(function () {
|
||||
var $this = $(this);
|
||||
var $ajaxLoading = $this.next('.ajaxLoading').show();
|
||||
var data = { FlattenForm: $this.is(':checked') };
|
||||
$.getJSON('@(Url.Action(MVC.API.DocumentTemplate.UpdateFlattenForm(Model.DocumentTemplate.Id)))', data, function (response, result) {
|
||||
if (result != 'success' || response != 'OK') {
|
||||
alert('Unable to change Flatten Form:\n' + response);
|
||||
$ajaxLoading.hide();
|
||||
} else {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
<input id="DocumentTemplate_FlattenForm" type="checkbox" @(Model.DocumentTemplate.FlattenForm ? new MvcHtmlString("checked=\"checked\" ") : new MvcHtmlString(string.Empty)) disabled="disabled" />
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Scope:
|
||||
</th>
|
||||
<td>
|
||||
<h4>@Model.DocumentTemplate.Scope Scope</h4>
|
||||
<div class="infoBox">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-info-circle"></i>This template is generated from @(Model.DocumentTemplate.Scope)s. Any expressions within the Template PDF will be evaluated within the <a href="@(Url.Action(MVC.Config.DocumentTemplate.ExpressionBrowser()))#@(Model.DocumentTemplate.Scope)Scope">@(Model.DocumentTemplate.Scope) Scope</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<button id="Config_DocumentTemplates_Scope_Button" class="button small">Change Scope</button>
|
||||
</div>
|
||||
@if (canConfig)
|
||||
{
|
||||
<a id="Config_DocumentTemplates_JobSubTypes_Update" href="#" class="button small">Update</a>
|
||||
<div id="Config_DocumentTemplates_JobSubTypes_Update_Dialog" class="dialog" title="Job Type Filter">
|
||||
@using (Html.BeginForm(MVC.API.DocumentTemplate.UpdateJobSubTypes(Model.DocumentTemplate.Id, null, true)))
|
||||
<div id="Config_DocumentTemplates_Scope_Dialog" title="Change Document Template Scope" class="dialog">
|
||||
@using (Html.BeginForm(MVC.API.DocumentTemplate.UpdateScope(Model.DocumentTemplate.Id, redirect: true)))
|
||||
{
|
||||
var selectedTypes = Model.DocumentTemplate.JobSubTypes.Select(jst => jst.JobType).Distinct().ToList();
|
||||
foreach (var jt in Model.JobTypes)
|
||||
{
|
||||
<div class="jobTypes">
|
||||
<h4>
|
||||
<input id="Types_@(jt.Id)" class="jobType" type="checkbox" value="@(jt.Id)" @(selectedTypes.Contains(jt) ? "checked=\"checked\"" : null) /><label for="Types_@(jt.Id)">@jt.Description</label></h4>
|
||||
<div id="SubTypes_@(jt.Id)" class="jobSubTypes">
|
||||
@CommonHelpers.CheckboxBulkSelect(string.Format("CheckboxBulkSelect_{0}", jt.Id), "div")
|
||||
@CommonHelpers.CheckBoxList("JobSubTypes", jt.JobSubTypes.OrderBy(jst => jst.Description).ToSelectListItems(Model.DocumentTemplate.JobSubTypes), 2)
|
||||
</div>
|
||||
<div class="input">
|
||||
<label for="Config_DocumentTemplates_Scope_Scope">Scope: </label>
|
||||
<select id="Config_DocumentTemplates_Scope_Scope" name="Scope">
|
||||
@foreach (var scope in Model.Scopes)
|
||||
{
|
||||
<option value="@scope" selected="@(scope == Model.DocumentTemplate.Scope ? "selected" : null)">@scope</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
}
|
||||
<div class="infoBox">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-info-circle"></i>Expressions within the Template PDF may need to be updated to reflect any changes to the Document Template Scope.
|
||||
</p>
|
||||
</div>
|
||||
@if (Model.DocumentTemplate.UsersLinkedGroup != null || Model.DocumentTemplate.DevicesLinkedGroup != null)
|
||||
{
|
||||
<div class="infoBox error">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-exclamation-circle"></i><strong>Warning:</strong> This Document Template contains Linked Groups, these will be automatically updated to reflect the new Document Template Scope which <strong>may result in undesired behaviour</strong>.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var dialog;
|
||||
|
||||
function showDialog() {
|
||||
if (!dialog) {
|
||||
dialog = $('#Config_DocumentTemplates_JobSubTypes_Update_Dialog').dialog({
|
||||
if (dialog == null) {
|
||||
dialog = $('#Config_DocumentTemplates_Scope_Dialog').dialog({
|
||||
width: 400,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 750,
|
||||
height: 620,
|
||||
buttons: {
|
||||
"Save Changes": saveChanges,
|
||||
Cancel: cancel
|
||||
'Save Changes': function () {
|
||||
dialog.dialog('option', 'buttons', null);
|
||||
dialog.dialog('disable');
|
||||
$('#Config_DocumentTemplates_Scope_Scope').closest('form').submit();
|
||||
},
|
||||
'Cancel': function () {
|
||||
dialog.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialog.find('.jobSubTypes').hide();
|
||||
dialog.on('change', 'input.jobType', function () {
|
||||
var $this = $(this);
|
||||
if ($this.is(':checked'))
|
||||
$('#SubTypes_' + $this.val()).slideDown('fast');
|
||||
else
|
||||
$('#SubTypes_' + $this.val()).slideUp('fast');
|
||||
}).find('input.jobType:checked').each(function () {
|
||||
$('#SubTypes_' + $(this).val()).show();
|
||||
});
|
||||
}
|
||||
|
||||
dialog.dialog('open');
|
||||
@@ -272,140 +216,321 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
dialog.dialog("disable");
|
||||
dialog.dialog("option", "buttons", null);
|
||||
|
||||
// Refresh Page
|
||||
window.location.href = window.location.href;
|
||||
}
|
||||
|
||||
function saveChanges() {
|
||||
var form = dialog.find('form');
|
||||
|
||||
$('input.jobType:unchecked').each(function () {
|
||||
$('#SubTypes_' + $(this).val()).find('input').prop('checked', false);
|
||||
});
|
||||
|
||||
form.submit();
|
||||
|
||||
dialog.dialog("disable");
|
||||
dialog.dialog("option", "buttons", null);
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('#Config_DocumentTemplates_JobSubTypes_Update').click(showDialog);
|
||||
});
|
||||
|
||||
})();
|
||||
$('#Config_DocumentTemplates_Scope_Button').click(showDialog);
|
||||
});
|
||||
</script>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Template PDF
|
||||
</th>
|
||||
<td>
|
||||
@Html.ActionLink("Download Template", MVC.API.DocumentTemplate.Template(Model.DocumentTemplate.Id))
|
||||
@if (canConfig && Authorization.Has(Claims.Config.DocumentTemplate.Upload))
|
||||
{
|
||||
<br />
|
||||
using (Html.BeginForm(MVC.API.DocumentTemplate.Template(Model.DocumentTemplate.Id, true, null), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
||||
{
|
||||
<input type="file" name="Template" id="Template" style="width: 250px;" />
|
||||
<input class="button" type="submit" value="Upload" />
|
||||
}
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $template = $('#Template');
|
||||
$template.closest('form').submit(function () {
|
||||
if ($template.val() == '') {
|
||||
alert('A template file is required to upload.');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Filter Expression:
|
||||
</th>
|
||||
<td>@if (canConfig && Authorization.Has(Claims.Config.DocumentTemplate.ConfigureFilterExpression))
|
||||
{
|
||||
@Html.TextBoxFor(model => model.DocumentTemplate.FilterExpression)
|
||||
@AjaxHelpers.AjaxRemove()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $FilterExpression = $('#DocumentTemplate_FilterExpression');
|
||||
var $ajaxLoading = $FilterExpression.nextAll('.ajaxLoading').first();
|
||||
var $ajaxRemove = $FilterExpression.nextAll('.ajaxRemove').first();
|
||||
$FilterExpression
|
||||
.watermark('Filter Expression')
|
||||
.focus(function () { $FilterExpression.select() })
|
||||
.keydown(function (e) {
|
||||
if (e.which == 13) {
|
||||
$(this).blur();
|
||||
@if (Model.DocumentTemplate.Scope == DocumentTemplate.DocumentTemplateScopes.Job)
|
||||
{
|
||||
<hr />
|
||||
<h4>Job Type Filters:</h4>
|
||||
<div id="Config_DocumentTemplates_JobSubTypes" @(Model.DocumentTemplate.Scope != DocumentTemplate.DocumentTemplateScopes.Job ? "style=\"display: none;\" " : null)>
|
||||
<div>
|
||||
@if (Model.DocumentTemplate.JobSubTypes.Count > 0)
|
||||
{
|
||||
<ul>
|
||||
@foreach (var jobType in Model.DocumentTemplate.JobSubTypes.GroupBy(jst => jst.JobType).OrderBy(jtg => jtg.Key.Description))
|
||||
{
|
||||
<li>
|
||||
@jobType.Key.Description
|
||||
<ul>
|
||||
@if (jobType.Count() == Model.JobTypes.FirstOrDefault(jt => jt.Id == jobType.Key.Id).JobSubTypes.Count)
|
||||
{
|
||||
<li><span class="smallMessage">[All Sub Types]</span></li>
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var jobSubType in jobType)
|
||||
{
|
||||
<li>@jobSubType.Description</li>
|
||||
}
|
||||
}
|
||||
</ul>
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
}).change(function () {
|
||||
updateFilterExpression($FilterExpression.val());
|
||||
else
|
||||
{
|
||||
<span class="smallMessage"><No Filter></span>
|
||||
}
|
||||
</div>
|
||||
@if (canConfig)
|
||||
{
|
||||
<a id="Config_DocumentTemplates_JobSubTypes_Update" href="#" class="button small">Update</a>
|
||||
<div id="Config_DocumentTemplates_JobSubTypes_Update_Dialog" class="dialog" title="Job Type Filter">
|
||||
@using (Html.BeginForm(MVC.API.DocumentTemplate.UpdateJobSubTypes(Model.DocumentTemplate.Id, null, true)))
|
||||
{
|
||||
var selectedTypes = Model.DocumentTemplate.JobSubTypes.Select(jst => jst.JobType).Distinct().ToList();
|
||||
foreach (var jt in Model.JobTypes)
|
||||
{
|
||||
<div class="jobTypes">
|
||||
<h4>
|
||||
<input id="Types_@(jt.Id)" class="jobType" type="checkbox" value="@(jt.Id)" @(selectedTypes.Contains(jt) ? "checked=\"checked\"" : null) /><label for="Types_@(jt.Id)">@jt.Description</label></h4>
|
||||
<div id="SubTypes_@(jt.Id)" class="jobSubTypes">
|
||||
@CommonHelpers.CheckboxBulkSelect(string.Format("CheckboxBulkSelect_{0}", jt.Id), "div")
|
||||
@CommonHelpers.CheckBoxList("JobSubTypes", jt.JobSubTypes.OrderBy(jst => jst.Description).ToSelectListItems(Model.DocumentTemplate.JobSubTypes), 2)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
(function () {
|
||||
var dialog;
|
||||
|
||||
function showDialog() {
|
||||
if (!dialog) {
|
||||
dialog = $('#Config_DocumentTemplates_JobSubTypes_Update_Dialog').dialog({
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 750,
|
||||
height: 620,
|
||||
buttons: {
|
||||
"Save Changes": saveChanges,
|
||||
Cancel: cancel
|
||||
}
|
||||
});
|
||||
|
||||
dialog.find('.jobSubTypes').hide();
|
||||
dialog.on('change', 'input.jobType', function () {
|
||||
var $this = $(this);
|
||||
if ($this.is(':checked'))
|
||||
$('#SubTypes_' + $this.val()).slideDown('fast');
|
||||
else
|
||||
$('#SubTypes_' + $this.val()).slideUp('fast');
|
||||
}).find('input.jobType:checked').each(function () {
|
||||
$('#SubTypes_' + $(this).val()).show();
|
||||
});
|
||||
}
|
||||
|
||||
dialog.dialog('open');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function cancel() {
|
||||
dialog.dialog("disable");
|
||||
dialog.dialog("option", "buttons", null);
|
||||
|
||||
// Refresh Page
|
||||
window.location.href = window.location.href;
|
||||
}
|
||||
|
||||
function saveChanges() {
|
||||
var form = dialog.find('form');
|
||||
|
||||
$('input.jobType:unchecked').each(function () {
|
||||
$('#SubTypes_' + $(this).val()).find('input').prop('checked', false);
|
||||
});
|
||||
|
||||
form.submit();
|
||||
|
||||
dialog.dialog("disable");
|
||||
dialog.dialog("option", "buttons", null);
|
||||
}
|
||||
|
||||
$(function () {
|
||||
$('#Config_DocumentTemplates_JobSubTypes_Update').click(showDialog);
|
||||
});
|
||||
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>PDF Template
|
||||
</th>
|
||||
<td>
|
||||
@Html.ActionLinkSmallButton("Download Template", MVC.API.DocumentTemplate.Template(Model.DocumentTemplate.Id))
|
||||
@if (canConfig && Authorization.Has(Claims.Config.DocumentTemplate.Upload))
|
||||
{
|
||||
<button class="button small" id="Config_DocumentTemplates_TemplatePdf_Button">Replace Template</button>
|
||||
<div id="Config_DocumentTemplates_TemplatePdf_Dialog" title="Replace Document PDF Template" class="dialog">
|
||||
<h4>Select a PDF Template to upload:</h4>
|
||||
<div>
|
||||
@using (Html.BeginForm(MVC.API.DocumentTemplate.Template(Model.DocumentTemplate.Id, true, null), FormMethod.Post, new { enctype = "multipart/form-data" }))
|
||||
{
|
||||
<input type="file" name="Template" id="Config_DocumentTemplates_TemplatePdf_Template" style="width: 250px;" />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var dialog, template;
|
||||
|
||||
function showDialog() {
|
||||
if (dialog == null) {
|
||||
template = $('#Config_DocumentTemplates_TemplatePdf_Template');
|
||||
|
||||
dialog = $('#Config_DocumentTemplates_TemplatePdf_Dialog').dialog({
|
||||
width: 350,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
buttons: {
|
||||
'Upload': function () {
|
||||
if (template.val() == '') {
|
||||
alert('A template file is required to upload.');
|
||||
} else {
|
||||
dialog.dialog('option', 'buttons', null);
|
||||
dialog.dialog('disable');
|
||||
template.closest('form').submit();
|
||||
}
|
||||
},
|
||||
'Cancel': function () {
|
||||
dialog.dialog('close');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
dialog.dialog('open');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$('#Config_DocumentTemplates_TemplatePdf_Button').click(showDialog);
|
||||
});
|
||||
if ($FilterExpression.val() != '')
|
||||
$ajaxRemove.show();
|
||||
$ajaxRemove.click(function () {
|
||||
updateFilterExpression('');
|
||||
$FilterExpression.val('');
|
||||
});
|
||||
var updateFilterExpression = function (filterExpression) {
|
||||
$ajaxLoading.show();
|
||||
$ajaxRemove.hide();
|
||||
var data = { FilterExpression: filterExpression };
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.DocumentTemplate.UpdateFilterExpression(Model.DocumentTemplate.Id))',
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d == 'OK') {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
if (data.FilterExpression != '')
|
||||
$ajaxRemove.fadeIn('fast');
|
||||
} else {
|
||||
$ajaxLoading.hide();
|
||||
alert('Unable to update filter expression: ' + d);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to update filter expression: ' + textStatus);
|
||||
$ajaxLoading.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
</script>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@if (hideAdvanced)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Model.DocumentTemplate.FilterExpression))
|
||||
{
|
||||
<span class="smallMessage"><None Specified></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="code">
|
||||
@Model.DocumentTemplate.FilterExpression
|
||||
</div>
|
||||
}
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;">
|
||||
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
|
||||
<script>
|
||||
$(function () {
|
||||
$('#Config_HideAdvanced_Show').click(function () {
|
||||
var $this = $(this);
|
||||
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
||||
$this.closest('tr').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="form Config_HideAdvanced_Item" style="width: 650px;">
|
||||
<h2>Advanced Options</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Filter Expression:
|
||||
</th>
|
||||
<td>@if (canConfig && Authorization.Has(Claims.Config.DocumentTemplate.ConfigureFilterExpression))
|
||||
{
|
||||
@Html.TextBoxFor(model => model.DocumentTemplate.FilterExpression)
|
||||
@AjaxHelpers.AjaxRemove()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var $FilterExpression = $('#DocumentTemplate_FilterExpression');
|
||||
var $ajaxLoading = $FilterExpression.nextAll('.ajaxLoading').first();
|
||||
var $ajaxRemove = $FilterExpression.nextAll('.ajaxRemove').first();
|
||||
$FilterExpression
|
||||
.watermark('Filter Expression')
|
||||
.focus(function () { $FilterExpression.select() })
|
||||
.keydown(function (e) {
|
||||
if (e.which == 13) {
|
||||
$(this).blur();
|
||||
}
|
||||
}).change(function () {
|
||||
updateFilterExpression($FilterExpression.val());
|
||||
});
|
||||
if ($FilterExpression.val() != '')
|
||||
$ajaxRemove.show();
|
||||
$ajaxRemove.click(function () {
|
||||
updateFilterExpression('');
|
||||
$FilterExpression.val('');
|
||||
});
|
||||
var updateFilterExpression = function (filterExpression) {
|
||||
$ajaxLoading.show();
|
||||
$ajaxRemove.hide();
|
||||
var data = { FilterExpression: filterExpression };
|
||||
$.ajax({
|
||||
url: '@Url.Action(MVC.API.DocumentTemplate.UpdateFilterExpression(Model.DocumentTemplate.Id))',
|
||||
dataType: 'json',
|
||||
data: data,
|
||||
success: function (d) {
|
||||
if (d == 'OK') {
|
||||
$ajaxLoading.hide().next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
if (data.FilterExpression != '')
|
||||
$ajaxRemove.fadeIn('fast');
|
||||
} else {
|
||||
$ajaxLoading.hide();
|
||||
alert('Unable to update filter expression: ' + d);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, textStatus, errorThrown) {
|
||||
alert('Unable to update filter expression: ' + textStatus);
|
||||
$ajaxLoading.hide();
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Model.DocumentTemplate.FilterExpression))
|
||||
{
|
||||
<span class="smallMessage"><None Specified></span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="code">
|
||||
@Model.DocumentTemplate.FilterExpression
|
||||
</div>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Linked Groups:
|
||||
</th>
|
||||
<td>
|
||||
<div>
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DocumentTemplateUsersManagedGroup.GetCategoryDescription(Model.DocumentTemplate),
|
||||
Description = DocumentTemplateUsersManagedGroup.GetDescription(Model.DocumentTemplate),
|
||||
ManagedGroup = Model.UsersLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DocumentTemplate.UpdateUsersLinkedGroup(Model.DocumentTemplate.Id, redirect: true))
|
||||
})
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = DocumentTemplateDevicesManagedGroup.GetCategoryDescription(Model.DocumentTemplate),
|
||||
Description = DocumentTemplateDevicesManagedGroup.GetDescription(Model.DocumentTemplate),
|
||||
ManagedGroup = Model.DevicesLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.DocumentTemplate.UpdateDevicesLinkedGroup(Model.DocumentTemplate.Id, redirect: true))
|
||||
})
|
||||
@if (canConfig)
|
||||
{
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="Config_HideAdvanced_Item">
|
||||
<h2>Template Expressions</h2>
|
||||
@Html.Partial(MVC.Config.DocumentTemplate.Views._ExpressionsTable, Model.TemplateExpressions)
|
||||
</div>
|
||||
</div>
|
||||
<h2>Template Expressions</h2>
|
||||
@Html.Partial(MVC.Config.DocumentTemplate.Views._ExpressionsTable, Model.TemplateExpressions)
|
||||
<div id="dialogConfirmDelete" title="Delete this Document Template?">
|
||||
<p>
|
||||
<i class="fa fa-exclamation-triangle fa-lg warning"></i>This item will be permanently deleted and cannot be recovered.<br />
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
@model Disco.Web.Areas.Config.Models.JobQueue.IndexModel
|
||||
@{
|
||||
Authorization.RequireAll(Claims.Config.JobQueue.Create, Claims.Config.JobQueue.Configure);
|
||||
Authorization.Require(Claims.Config.JobQueue.Show);
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Job Queues", MVC.Config.JobQueue.Index(null));
|
||||
}
|
||||
<div id="Config_JobQueues_Index">
|
||||
@@ -54,7 +54,10 @@
|
||||
}
|
||||
</table>
|
||||
}
|
||||
<div class="actionBar">
|
||||
@Html.ActionLinkButton("Create Job Queue", MVC.Config.JobQueue.Create())
|
||||
</div>
|
||||
@if (Authorization.Has(Claims.Config.JobQueue.Create))
|
||||
{
|
||||
<div class="actionBar">
|
||||
@Html.ActionLinkButton("Create Job Queue", MVC.Config.JobQueue.Create())
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Disco.Web.Areas.Config.Views.JobQueue
|
||||
|
||||
#line 2 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
|
||||
Authorization.RequireAll(Claims.Config.JobQueue.Create, Claims.Config.JobQueue.Configure);
|
||||
Authorization.Require(Claims.Config.JobQueue.Show);
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "Job Queues", MVC.Config.JobQueue.Index(null));
|
||||
|
||||
|
||||
@@ -114,37 +114,37 @@ WriteLiteral(">\r\n <tr>\r\n <th>Name</th>\r\n
|
||||
#line hidden
|
||||
WriteLiteral(" <tr>\r\n <td>\r\n <a");
|
||||
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 890), Tuple.Create("\"", 953)
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 851), Tuple.Create("\"", 914)
|
||||
|
||||
#line 26 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 897), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Config.JobQueue.Index(item.JobQueue.Id))
|
||||
, Tuple.Create(Tuple.Create("", 858), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Config.JobQueue.Index(item.JobQueue.Id))
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 897), false)
|
||||
, 858), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 987), Tuple.Create("\"", 1058)
|
||||
, Tuple.Create(Tuple.Create("", 995), Tuple.Create("fa", 995), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 997), Tuple.Create("fa-", 998), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 948), Tuple.Create("\"", 1019)
|
||||
, Tuple.Create(Tuple.Create("", 956), Tuple.Create("fa", 956), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 958), Tuple.Create("fa-", 959), true)
|
||||
|
||||
#line 27 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1001), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Icon
|
||||
, Tuple.Create(Tuple.Create("", 962), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Icon
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1001), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 1022), Tuple.Create("fa-lg", 1023), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 1028), Tuple.Create("d-", 1029), true)
|
||||
, 962), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 983), Tuple.Create("fa-lg", 984), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 989), Tuple.Create("d-", 990), true)
|
||||
|
||||
#line 27 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1031), Tuple.Create<System.Object, System.Int32>(item.JobQueue.IconColour
|
||||
, Tuple.Create(Tuple.Create("", 992), Tuple.Create<System.Object, System.Int32>(item.JobQueue.IconColour
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1031), false)
|
||||
, 992), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
@@ -201,27 +201,27 @@ WriteLiteral("><none></span>\r\n");
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n <td>\r\n <i");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 1613), Tuple.Create("\"", 1681)
|
||||
, Tuple.Create(Tuple.Create("", 1621), Tuple.Create("fa", 1621), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 1623), Tuple.Create("d-priority-", 1624), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 1574), Tuple.Create("\"", 1642)
|
||||
, Tuple.Create(Tuple.Create("", 1582), Tuple.Create("fa", 1582), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 1584), Tuple.Create("d-priority-", 1585), true)
|
||||
|
||||
#line 41 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1635), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Priority.ToString().ToLower()
|
||||
, Tuple.Create(Tuple.Create("", 1596), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Priority.ToString().ToLower()
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1635), false)
|
||||
, 1596), false)
|
||||
);
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 1682), Tuple.Create("\"", 1735)
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 1643), Tuple.Create("\"", 1696)
|
||||
|
||||
#line 41 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1690), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Priority.ToString()
|
||||
, Tuple.Create(Tuple.Create("", 1651), Tuple.Create<System.Object, System.Int32>(item.JobQueue.Priority.ToString()
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1690), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 1726), Tuple.Create("Priority", 1727), true)
|
||||
, 1651), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 1687), Tuple.Create("Priority", 1688), true)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n </td>\r\n <td>\r\n");
|
||||
@@ -288,22 +288,41 @@ WriteLiteral(" </table>\r\n");
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 57 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
if (Authorization.Has(Claims.Config.JobQueue.Create))
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"actionBar\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 58 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Create Job Queue", MVC.Config.JobQueue.Create()));
|
||||
#line 60 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Create Job Queue", MVC.Config.JobQueue.Create()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </div>\r\n</div>\r\n");
|
||||
WriteLiteral("\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 62 "..\..\Areas\Config\Views\JobQueue\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</div>\r\n");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,15 +64,14 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
<pre>
|
||||
@if (string.IsNullOrEmpty(Model.Token.JobQueue.Description))
|
||||
{
|
||||
<pre>@if (string.IsNullOrEmpty(Model.Token.JobQueue.Description))
|
||||
{
|
||||
<text><None></text>
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.Token.JobQueue.Description.ToHtmlComment()
|
||||
}
|
||||
}
|
||||
</pre>
|
||||
}
|
||||
</td>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
@model Disco.Web.Areas.Config.Models.Shared.LinkedGroupModel
|
||||
@using Disco.Services.Interop.ActiveDirectory;
|
||||
<h5>@(Model.CategoryDescription)</h5>
|
||||
<div class="Config_LinkedGroup_Instance">
|
||||
<div class="infoBox">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-fw fa-info-circle"></i>@Model.Description
|
||||
</p>
|
||||
</div>
|
||||
@{
|
||||
ADGroup group = null;
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
group = Model.ManagedGroup.GetGroup();
|
||||
}
|
||||
if (Model.CanConfigure)
|
||||
{
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
<div class="code" title="@group.Id">
|
||||
<i class="fa fa-fw fa-lg fa-link success"></i>@group.Domain.FriendlyDistinguishedNamePath(group.DistinguishedName)
|
||||
</div>
|
||||
<button class="button small Config_LinkedGroup_LinkButton" data-linkedgroupid="@(Model.ManagedGroup.Configuration.GroupId)" data-linkedroupdescription="@(Model.CategoryDescription)" data-linkedroupupdateurl="@(Model.UpdateUrl)">Change Link</button>
|
||||
<a href="@(Url.Action(MVC.API.System.SyncActiveDirectoryManagedGroup(Model.ManagedGroup.Key, Context.Request.Path)))" class="button small">Synchronize Now</a>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="code error">
|
||||
<i class="fa fa-fw fa-lg fa-unlink error"></i>Group Not Found: <strong class="code">@Model.ManagedGroup.Configuration.GroupId</strong>
|
||||
</div>
|
||||
<button class="button small Config_LinkedGroup_LinkButton" data-linkedgroupid="@(Model.ManagedGroup.Configuration.GroupId)" data-linkedroupdescription="@(Model.CategoryDescription)" data-linkedroupupdateurl="@(Model.UpdateUrl)">Change Link</button>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<button class="button small Config_LinkedGroup_LinkButton" data-linkedgroupid="" data-linkedroupdescription="@(Model.CategoryDescription)" data-linkedroupupdateurl="@(Model.UpdateUrl)">Link Group</button>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
<div class="code" title="@group.Id">
|
||||
<i class="fa fa-fw fa-lg fa-link success"></i>@group.Domain.FriendlyDistinguishedNamePath(group.DistinguishedName)
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="code error">
|
||||
<i class="fa fa-fw fa-lg fa-unlink error"></i>Group Not Found: <strong class="code">@Model.ManagedGroup.Configuration.GroupId</strong>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="smallMessage"><i class="fa fa-fw fa-lg fa-unlink information"></i>No Group Linked</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,416 @@
|
||||
#pragma warning disable 1591
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Disco.Web.Areas.Config.Views.Shared
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Ajax;
|
||||
using System.Web.Mvc.Html;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.UI;
|
||||
using System.Web.WebPages;
|
||||
using Disco;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services;
|
||||
using Disco.Services.Authorization;
|
||||
|
||||
#line 2 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web;
|
||||
using Disco.Web.Extensions;
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Shared/LinkedGroupInstance.cshtml")]
|
||||
public partial class LinkedGroupInstance : Disco.Services.Web.WebViewPage<Disco.Web.Areas.Config.Models.Shared.LinkedGroupModel>
|
||||
{
|
||||
public LinkedGroupInstance()
|
||||
{
|
||||
}
|
||||
public override void Execute()
|
||||
{
|
||||
WriteLiteral("<h5>");
|
||||
|
||||
|
||||
#line 3 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.CategoryDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</h5>\r\n<div");
|
||||
|
||||
WriteLiteral(" class=\"Config_LinkedGroup_Instance\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"infoBox\"");
|
||||
|
||||
WriteLiteral(">\r\n <p");
|
||||
|
||||
WriteLiteral(" class=\"fa-p\"");
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-info-circle\"");
|
||||
|
||||
WriteLiteral("></i>");
|
||||
|
||||
|
||||
#line 7 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.Description);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </p>\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 10 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 10 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
|
||||
ADGroup group = null;
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
group = Model.ManagedGroup.GetGroup();
|
||||
}
|
||||
if (Model.CanConfigure)
|
||||
{
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 680), Tuple.Create("\"", 697)
|
||||
|
||||
#line 22 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 688), Tuple.Create<System.Object, System.Int32>(group.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 688), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-lg fa-link success\"");
|
||||
|
||||
WriteLiteral("></i>");
|
||||
|
||||
|
||||
#line 23 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(group.Domain.FriendlyDistinguishedNamePath(group.DistinguishedName));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </div>\r\n");
|
||||
|
||||
WriteLiteral(" <button");
|
||||
|
||||
WriteLiteral(" class=\"button small Config_LinkedGroup_LinkButton\"");
|
||||
|
||||
WriteLiteral(" data-linkedgroupid=\"");
|
||||
|
||||
|
||||
#line 25 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.ManagedGroup.Configuration.GroupId);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupdescription=\"");
|
||||
|
||||
|
||||
#line 25 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.CategoryDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupupdateurl=\"");
|
||||
|
||||
|
||||
#line 25 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.UpdateUrl);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(">Change Link</button>\r\n");
|
||||
|
||||
WriteLiteral(" <a");
|
||||
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 1113), Tuple.Create("\"", 1227)
|
||||
|
||||
#line 26 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1120), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.System.SyncActiveDirectoryManagedGroup(Model.ManagedGroup.Key, Context.Request.Path))
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1120), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" class=\"button small\"");
|
||||
|
||||
WriteLiteral(">Synchronize Now</a>\r\n");
|
||||
|
||||
|
||||
#line 27 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"code error\"");
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-lg fa-unlink error\"");
|
||||
|
||||
WriteLiteral("></i>Group Not Found: <strong");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteLiteral(">");
|
||||
|
||||
|
||||
#line 31 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.ManagedGroup.Configuration.GroupId);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</strong>\r\n </div> \r\n");
|
||||
|
||||
WriteLiteral(" <button");
|
||||
|
||||
WriteLiteral(" class=\"button small Config_LinkedGroup_LinkButton\"");
|
||||
|
||||
WriteLiteral(" data-linkedgroupid=\"");
|
||||
|
||||
|
||||
#line 33 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.ManagedGroup.Configuration.GroupId);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupdescription=\"");
|
||||
|
||||
|
||||
#line 33 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.CategoryDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupupdateurl=\"");
|
||||
|
||||
|
||||
#line 33 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.UpdateUrl);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(">Change Link</button>\r\n");
|
||||
|
||||
|
||||
#line 34 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <button");
|
||||
|
||||
WriteLiteral(" class=\"button small Config_LinkedGroup_LinkButton\"");
|
||||
|
||||
WriteLiteral(" data-linkedgroupid=\"\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupdescription=\"");
|
||||
|
||||
|
||||
#line 38 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.CategoryDescription);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(" data-linkedroupupdateurl=\"");
|
||||
|
||||
|
||||
#line 38 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.UpdateUrl);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteLiteral(">Link Group</button>\r\n");
|
||||
|
||||
|
||||
#line 39 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Model.ManagedGroup != null)
|
||||
{
|
||||
if (group != null)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 2271), Tuple.Create("\"", 2288)
|
||||
|
||||
#line 47 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 2279), Tuple.Create<System.Object, System.Int32>(group.Id
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 2279), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-lg fa-link success\"");
|
||||
|
||||
WriteLiteral("></i>");
|
||||
|
||||
|
||||
#line 48 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(group.Domain.FriendlyDistinguishedNamePath(group.DistinguishedName));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 50 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"code error\"");
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-lg fa-unlink error\"");
|
||||
|
||||
WriteLiteral("></i>Group Not Found: <strong");
|
||||
|
||||
WriteLiteral(" class=\"code\"");
|
||||
|
||||
WriteLiteral(">");
|
||||
|
||||
|
||||
#line 54 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
Write(Model.ManagedGroup.Configuration.GroupId);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</strong>\r\n </div> \r\n");
|
||||
|
||||
|
||||
#line 56 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"smallMessage\"");
|
||||
|
||||
WriteLiteral("><i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-fw fa-lg fa-unlink information\"");
|
||||
|
||||
WriteLiteral("></i>No Group Linked</div>\r\n");
|
||||
|
||||
|
||||
#line 61 "..\..\Areas\Config\Views\Shared\LinkedGroupInstance.cshtml"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n</div>\r\n");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
@@ -0,0 +1,89 @@
|
||||
<div id="Config_LinkedGroup_Dialog" title="Linked Group" class="dialog">
|
||||
<h3 id="Config_LinkedGroup_Title"></h3>
|
||||
<div class="infoBox error">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-exclamation-circle"></i><strong>Warning:</strong> This group will be managed by Disco ICT.<br />
|
||||
Any <strong>existing members will be removed from the group</strong>, and it will be automatically synchronized with related members.
|
||||
</p>
|
||||
</div>
|
||||
<form action="#" method="post">
|
||||
<div class="input">
|
||||
<label for="Config_LinkedGroup_Id">Linked Group: </label>
|
||||
<input id="Config_LinkedGroup_Id" type="text" name="GroupId" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
var dialog;
|
||||
var dialogGroupId;
|
||||
var dialogTitle;
|
||||
|
||||
function showDialog(groupId, updateUrl, title) {
|
||||
if (dialog == null) {
|
||||
dialog = $('#Config_LinkedGroup_Dialog').dialog({
|
||||
width: 450,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false
|
||||
});
|
||||
|
||||
dialogGroupId = $('#Config_LinkedGroup_Id');
|
||||
dialogGroupId.focus(function () { $(this).select(); });
|
||||
dialogGroupId.autocomplete({
|
||||
source: '@(Url.Action(MVC.API.System.SearchGroupSubjects()))',
|
||||
minLength: 2,
|
||||
select: function (e, ui) {
|
||||
dialogGroupId.val(ui.item.Id);
|
||||
return false;
|
||||
}
|
||||
}).data('ui-autocomplete')._renderItem = function (ul, item) {
|
||||
return $("<li>")
|
||||
.data("item.autocomplete", item)
|
||||
.append("<a><strong>" + item.Name + "</strong><br>" + item.Id + " (" + item.Type + ")</a>")
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
dialogTitle = $('#Config_LinkedGroup_Title');
|
||||
}
|
||||
|
||||
var dialogButtons = {};
|
||||
if (!!groupId) {
|
||||
dialogButtons['Remove Link'] = function () {
|
||||
$(this).dialog('disable');
|
||||
dialogGroupId.val('');
|
||||
dialogGroupId.closest('form').attr('action', updateUrl).submit();
|
||||
}
|
||||
}
|
||||
dialogButtons[(!!groupId ? 'Save Changes' : 'Link Group')] = function () {
|
||||
if (!dialogGroupId.val()) {
|
||||
alert('A Linked Group must be specified');
|
||||
return;
|
||||
}
|
||||
$(this).dialog('disable');
|
||||
dialogGroupId.closest('form').attr('action', updateUrl).submit();
|
||||
}
|
||||
dialogButtons['Cancel'] = function () {
|
||||
$(this).dialog('close');
|
||||
};
|
||||
|
||||
dialogGroupId.val(groupId);
|
||||
dialogTitle.text(title);
|
||||
dialog.dialog('option', 'buttons', dialogButtons);
|
||||
dialog.dialog('option', 'title', 'Linked Group: ' + title);
|
||||
dialog.dialog('open');
|
||||
}
|
||||
|
||||
$(document).on('click', '.Config_LinkedGroup_LinkButton', function () {
|
||||
$this = $(this);
|
||||
|
||||
var configuredGroupId = $this.attr('data-linkedgroupid');
|
||||
var description = $this.attr('data-linkedroupdescription');
|
||||
var updateUrl = $this.attr('data-linkedroupupdateurl');
|
||||
|
||||
showDialog(configuredGroupId, updateUrl, description);
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,160 @@
|
||||
#pragma warning disable 1591
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.34014
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Disco.Web.Areas.Config.Views.Shared
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using System.Web.Helpers;
|
||||
using System.Web.Mvc;
|
||||
using System.Web.Mvc.Ajax;
|
||||
using System.Web.Mvc.Html;
|
||||
using System.Web.Routing;
|
||||
using System.Web.Security;
|
||||
using System.Web.UI;
|
||||
using System.Web.WebPages;
|
||||
using Disco;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services;
|
||||
using Disco.Services.Authorization;
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web;
|
||||
using Disco.Web.Extensions;
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
[System.Web.WebPages.PageVirtualPathAttribute("~/Areas/Config/Views/Shared/LinkedGroupShared.cshtml")]
|
||||
public partial class LinkedGroupShared : Disco.Services.Web.WebViewPage<dynamic>
|
||||
{
|
||||
public LinkedGroupShared()
|
||||
{
|
||||
}
|
||||
public override void Execute()
|
||||
{
|
||||
WriteLiteral("<div");
|
||||
|
||||
WriteLiteral(" id=\"Config_LinkedGroup_Dialog\"");
|
||||
|
||||
WriteLiteral(" title=\"Linked Group\"");
|
||||
|
||||
WriteLiteral(" class=\"dialog\"");
|
||||
|
||||
WriteLiteral(">\r\n <h3");
|
||||
|
||||
WriteLiteral(" id=\"Config_LinkedGroup_Title\"");
|
||||
|
||||
WriteLiteral("></h3>\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"infoBox error\"");
|
||||
|
||||
WriteLiteral(">\r\n <p");
|
||||
|
||||
WriteLiteral(" class=\"fa-p\"");
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-exclamation-circle\"");
|
||||
|
||||
WriteLiteral(@"></i><strong>Warning:</strong> This group will be managed by Disco ICT.<br />
|
||||
Any <strong>existing members will be removed from the group</strong>, and it will be automatically synchronized with related members.
|
||||
</p>
|
||||
</div>
|
||||
<form");
|
||||
|
||||
WriteLiteral(" action=\"#\"");
|
||||
|
||||
WriteLiteral(" method=\"post\"");
|
||||
|
||||
WriteLiteral(">\r\n <div");
|
||||
|
||||
WriteLiteral(" class=\"input\"");
|
||||
|
||||
WriteLiteral(">\r\n <label");
|
||||
|
||||
WriteLiteral(" for=\"Config_LinkedGroup_Id\"");
|
||||
|
||||
WriteLiteral(">Linked Group: </label>\r\n <input");
|
||||
|
||||
WriteLiteral(" id=\"Config_LinkedGroup_Id\"");
|
||||
|
||||
WriteLiteral(" type=\"text\"");
|
||||
|
||||
WriteLiteral(" name=\"GroupId\"");
|
||||
|
||||
WriteLiteral(@" />
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
var dialog;
|
||||
var dialogGroupId;
|
||||
var dialogTitle;
|
||||
|
||||
function showDialog(groupId, updateUrl, title) {
|
||||
if (dialog == null) {
|
||||
dialog = $('#Config_LinkedGroup_Dialog').dialog({
|
||||
width: 450,
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false
|
||||
});
|
||||
|
||||
dialogGroupId = $('#Config_LinkedGroup_Id');
|
||||
dialogGroupId.focus(function () { $(this).select(); });
|
||||
dialogGroupId.autocomplete({
|
||||
source: '");
|
||||
|
||||
|
||||
#line 34 "..\..\Areas\Config\Views\Shared\LinkedGroupShared.cshtml"
|
||||
Write(Url.Action(MVC.API.System.SearchGroupSubjects()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\',\r\n minLength: 2,\r\n select: function (e, u" +
|
||||
"i) {\r\n dialogGroupId.val(ui.item.Id);\r\n " +
|
||||
" return false;\r\n }\r\n }).data(\'ui-autocomp" +
|
||||
"lete\')._renderItem = function (ul, item) {\r\n return $(\"<li>\")" +
|
||||
"\r\n .data(\"item.autocomplete\", item)\r\n " +
|
||||
" .append(\"<a><strong>\" + item.Name + \"</strong><br>\" + item.Id + \" (\" + item." +
|
||||
"Type + \")</a>\")\r\n .appendTo(ul);\r\n };\r\n\r\n " +
|
||||
" dialogTitle = $(\'#Config_LinkedGroup_Title\');\r\n }\r\n\r\n " +
|
||||
" var dialogButtons = {};\r\n if (!!groupId) {\r\n " +
|
||||
" dialogButtons[\'Remove Link\'] = function () {\r\n $(this).dial" +
|
||||
"og(\'disable\');\r\n dialogGroupId.val(\'\');\r\n " +
|
||||
"dialogGroupId.closest(\'form\').attr(\'action\', updateUrl).submit();\r\n " +
|
||||
" }\r\n }\r\n dialogButtons[(!!groupId ? \'Save Changes\' : \'Li" +
|
||||
"nk Group\')] = function () {\r\n if (!dialogGroupId.val()) {\r\n " +
|
||||
" alert(\'A Linked Group must be specified\');\r\n re" +
|
||||
"turn;\r\n }\r\n $(this).dialog(\'disable\');\r\n " +
|
||||
" dialogGroupId.closest(\'form\').attr(\'action\', updateUrl).submit();\r\n " +
|
||||
" }\r\n dialogButtons[\'Cancel\'] = function () {\r\n $(t" +
|
||||
"his).dialog(\'close\');\r\n };\r\n\r\n dialogGroupId.val(groupId);" +
|
||||
"\r\n dialogTitle.text(title);\r\n dialog.dialog(\'option\', \'but" +
|
||||
"tons\', dialogButtons);\r\n dialog.dialog(\'option\', \'title\', \'Linked Gro" +
|
||||
"up: \' + title);\r\n dialog.dialog(\'open\');\r\n }\r\n\r\n $(docu" +
|
||||
"ment).on(\'click\', \'.Config_LinkedGroup_LinkButton\', function () {\r\n $" +
|
||||
"this = $(this);\r\n\r\n var configuredGroupId = $this.attr(\'data-linkedgr" +
|
||||
"oupid\');\r\n var description = $this.attr(\'data-linkedroupdescription\')" +
|
||||
";\r\n var updateUrl = $this.attr(\'data-linkedroupupdateurl\');\r\n\r\n " +
|
||||
" showDialog(configuredGroupId, updateUrl, description);\r\n\r\n retu" +
|
||||
"rn false;\r\n });\r\n });\r\n</script>\r\n");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
@@ -1,6 +1,6 @@
|
||||
@model Disco.Web.Areas.Config.Models.UserFlag.IndexModel
|
||||
@{
|
||||
Authorization.RequireAll(Claims.Config.UserFlag.Create, Claims.Config.UserFlag.Configure);
|
||||
Authorization.Require(Claims.Config.UserFlag.Show);
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "User Flags", MVC.Config.UserFlag.Index(null));
|
||||
}
|
||||
<div id="Config_UserFlags_Index">
|
||||
@@ -16,6 +16,7 @@
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>Linked</th>
|
||||
</tr>
|
||||
@foreach (var item in Model.UserFlags)
|
||||
{
|
||||
@@ -35,11 +36,23 @@
|
||||
@item.Description.ToHtmlComment()
|
||||
}
|
||||
</td>
|
||||
<td>@if (item.UserDevicesLinkedGroup != null || item.UsersLinkedGroup != null)
|
||||
{
|
||||
<i class="fa fa-link fa-lg success"></i>
|
||||
}
|
||||
else
|
||||
{
|
||||
<i class="fa fa-unlink fa-lg information"></i>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</table>
|
||||
}
|
||||
<div class="actionBar">
|
||||
@Html.ActionLinkButton("Create User Flag", MVC.Config.UserFlag.Create())
|
||||
</div>
|
||||
@if (Authorization.Has(Claims.Config.UserFlag.Create))
|
||||
{
|
||||
<div class="actionBar">
|
||||
@Html.ActionLinkButton("Create User Flag", MVC.Config.UserFlag.Create())
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -47,7 +47,7 @@ namespace Disco.Web.Areas.Config.Views.UserFlag
|
||||
|
||||
#line 2 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
|
||||
Authorization.RequireAll(Claims.Config.UserFlag.Create, Claims.Config.UserFlag.Configure);
|
||||
Authorization.Require(Claims.Config.UserFlag.Show);
|
||||
ViewBag.Title = Html.ToBreadcrumb("Configuration", MVC.Config.Config.Index(), "User Flags", MVC.Config.UserFlag.Index(null));
|
||||
|
||||
|
||||
@@ -95,16 +95,16 @@ WriteLiteral(" <table");
|
||||
WriteLiteral(" class=\"tableData\"");
|
||||
|
||||
WriteLiteral(">\r\n <tr>\r\n <th>Name</th>\r\n <th>Descripti" +
|
||||
"on</th>\r\n </tr>\r\n");
|
||||
"on</th>\r\n <th>Linked</th>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 20 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 21 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 20 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 21 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
foreach (var item in Model.UserFlags)
|
||||
{
|
||||
|
||||
@@ -113,37 +113,37 @@ WriteLiteral(">\r\n <tr>\r\n <th>Name</th>\r\n
|
||||
#line hidden
|
||||
WriteLiteral(" <tr>\r\n <td>\r\n <a");
|
||||
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 815), Tuple.Create("\"", 869)
|
||||
WriteAttribute("href", Tuple.Create(" href=\"", 809), Tuple.Create("\"", 863)
|
||||
|
||||
#line 24 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 822), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Config.UserFlag.Index(item.Id))
|
||||
#line 25 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 816), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Config.UserFlag.Index(item.Id))
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 822), false)
|
||||
, 816), false)
|
||||
);
|
||||
|
||||
WriteLiteral(">\r\n <i");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 903), Tuple.Create("\"", 956)
|
||||
, Tuple.Create(Tuple.Create("", 911), Tuple.Create("fa", 911), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 913), Tuple.Create("fa-", 914), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 897), Tuple.Create("\"", 950)
|
||||
, Tuple.Create(Tuple.Create("", 905), Tuple.Create("fa", 905), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 907), Tuple.Create("fa-", 908), true)
|
||||
|
||||
#line 25 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 917), Tuple.Create<System.Object, System.Int32>(item.Icon
|
||||
#line 26 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 911), Tuple.Create<System.Object, System.Int32>(item.Icon
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 917), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 929), Tuple.Create("fa-lg", 930), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 935), Tuple.Create("d-", 936), true)
|
||||
, 911), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 923), Tuple.Create("fa-lg", 924), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 929), Tuple.Create("d-", 930), true)
|
||||
|
||||
#line 25 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 938), Tuple.Create<System.Object, System.Int32>(item.IconColour
|
||||
#line 26 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 932), Tuple.Create<System.Object, System.Int32>(item.IconColour
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 938), false)
|
||||
, 932), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
@@ -151,7 +151,7 @@ WriteLiteral("></i>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 26 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 27 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
Write(item.Name);
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ WriteLiteral("\r\n </a>\r\n </td>\r\n
|
||||
"d>");
|
||||
|
||||
|
||||
#line 29 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 30 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
if (string.IsNullOrWhiteSpace(item.Description))
|
||||
{
|
||||
|
||||
@@ -175,7 +175,7 @@ WriteLiteral(" class=\"smallMessage\"");
|
||||
WriteLiteral("><none></span>\r\n");
|
||||
|
||||
|
||||
#line 32 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 33 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -184,24 +184,62 @@ WriteLiteral("><none></span>\r\n");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 35 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 36 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
Write(item.Description.ToHtmlComment());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 35 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 36 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n <td>");
|
||||
|
||||
|
||||
#line 39 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
if (item.UserDevicesLinkedGroup != null || item.UsersLinkedGroup != null)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-link fa-lg success\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 42 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <i");
|
||||
|
||||
WriteLiteral(" class=\"fa fa-unlink fa-lg information\"");
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 46 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 39 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 49 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -210,28 +248,47 @@ WriteLiteral(" </td>\r\n </tr>\r\n");
|
||||
WriteLiteral(" </table>\r\n");
|
||||
|
||||
|
||||
#line 41 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
#line 51 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 52 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
if (Authorization.Has(Claims.Config.UserFlag.Create))
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <div");
|
||||
|
||||
WriteLiteral(" class=\"actionBar\"");
|
||||
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 43 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Create User Flag", MVC.Config.UserFlag.Create()));
|
||||
#line 55 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
Write(Html.ActionLinkButton("Create User Flag", MVC.Config.UserFlag.Create()));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n </div>\r\n</div>\r\n");
|
||||
WriteLiteral("\r\n </div>\r\n");
|
||||
|
||||
|
||||
#line 57 "..\..\Areas\Config\Views\UserFlag\Index.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("</div>");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
@model Disco.Web.Areas.Config.Models.UserFlag.ShowModel
|
||||
@using Disco.Services.Users.UserFlags;
|
||||
@using Disco.Services.Interop.ActiveDirectory;
|
||||
@using Disco.Services.Users.UserFlags;
|
||||
@using Disco.Web.Areas.Config.Models.Shared;
|
||||
@{
|
||||
Authorization.Require(Claims.Config.UserFlag.Show);
|
||||
|
||||
@@ -11,9 +12,13 @@
|
||||
var canBulkAssignment = Authorization.HasAll(Claims.User.Actions.AddFlags, Claims.User.Actions.RemoveFlags, Claims.User.ShowFlagAssignments);
|
||||
var canShowUsers = Model.CurrentAssignmentCount > 0 && Authorization.HasAll(Claims.User.Search, Claims.User.ShowFlagAssignments);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.UserFlag.UserDevicesLinkedGroup == null &&
|
||||
Model.UserFlag.UsersLinkedGroup == null;
|
||||
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers");
|
||||
}
|
||||
<div id="Config_UserFlags_Show" class="form" style="width: 550px">
|
||||
<div id="Config_UserFlags_Show" class="form@(hideAdvanced ? " Config_HideAdvanced" : null)" style="width: 550px">
|
||||
<table>
|
||||
<tr>
|
||||
<th style="width: 150px">Id:
|
||||
@@ -193,6 +198,51 @@
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
@if (hideAdvanced)
|
||||
{
|
||||
<tr>
|
||||
<td colspan="2" style="text-align: right;">
|
||||
<button id="Config_HideAdvanced_Show" class="button small">Show Advanced Options</button>
|
||||
<script>
|
||||
$(function () {
|
||||
$('#Config_HideAdvanced_Show').click(function () {
|
||||
var $this = $(this);
|
||||
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
||||
$this.closest('tr').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>Linked Groups:
|
||||
</th>
|
||||
<td>
|
||||
<div>
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = UserFlagUsersManagedGroup.GetCategoryDescription(Model.UserFlag),
|
||||
Description = UserFlagUsersManagedGroup.GetDescription(Model.UserFlag),
|
||||
ManagedGroup = Model.UsersLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUsersLinkedGroup(Model.UserFlag.Id, redirect: true))
|
||||
})
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = UserFlagUserDevicesManagedGroup.GetCategoryDescription(Model.UserFlag),
|
||||
Description = UserFlagUserDevicesManagedGroup.GetDescription(Model.UserFlag),
|
||||
ManagedGroup = Model.UserDevicesLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUserDevicesLinkedGroup(Model.UserFlag.Id, redirect: true))
|
||||
})
|
||||
@if (canConfig)
|
||||
{
|
||||
@Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared)
|
||||
}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@if (canBulkAssignment || canDelete || canShowUsers)
|
||||
@@ -241,7 +291,7 @@
|
||||
<h4><i class="fa fa-lg fa-cog fa-spin" title="Please Wait"></i>Loading current assignments...</h4>
|
||||
</div>
|
||||
<form action="#" method="post">
|
||||
<textarea id="Config_UserFlags_BulkAssign_AssignDialog_UserIds" name="UserIds" data-val="true"></textarea>
|
||||
<textarea id="Config_UserFlags_BulkAssign_AssignDialog_UserIds" name="UserIds"></textarea>
|
||||
<h4>Comments:</h4>
|
||||
<textarea id="Config_UserFlags_BulkAssign_AssignDialog_Comments" name="Comments"></textarea>
|
||||
</form>
|
||||
@@ -303,35 +353,35 @@
|
||||
if (mode == "Override") {
|
||||
assignUserIds.closest('form').attr('action', '@(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, true)))');
|
||||
|
||||
assignDialog.addClass('loading');
|
||||
$.getJSON('@Url.Action(MVC.API.UserFlag.AssignedUsers(Model.UserFlag.Id))', function (response, result) {
|
||||
assignDialog.removeClass('loading');
|
||||
assignDialog.addClass('loading');
|
||||
$.getJSON('@Url.Action(MVC.API.UserFlag.AssignedUsers(Model.UserFlag.Id))', function (response, result) {
|
||||
assignDialog.removeClass('loading');
|
||||
|
||||
if (result != 'success') {
|
||||
alert('Unable to load current assignments:\n' + response);
|
||||
assignDialog.dialog('close');
|
||||
} else {
|
||||
if (!!response) {
|
||||
assignUserIds.val(response.join('\n'));
|
||||
} else {
|
||||
assignUserIds.val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result != 'success') {
|
||||
alert('Unable to load current assignments:\n' + response);
|
||||
assignDialog.dialog('close');
|
||||
} else {
|
||||
if (!!response) {
|
||||
assignUserIds.val(response.join('\n'));
|
||||
} else {
|
||||
assignUserIds.val('');
|
||||
}
|
||||
}
|
||||
else // Assume Add
|
||||
{
|
||||
assignUserIds.closest('form').attr('action', '@(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, false)))');
|
||||
}
|
||||
|
||||
assignDialog.dialog('open');
|
||||
}
|
||||
|
||||
$('#Config_UserFlags_BulkAssign_Button').click(function () {
|
||||
showModeDialog();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
}
|
||||
else // Assume Add
|
||||
{
|
||||
assignUserIds.closest('form').attr('action', '@(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, false)))');
|
||||
}
|
||||
|
||||
assignDialog.dialog('open');
|
||||
}
|
||||
|
||||
$('#Config_UserFlags_BulkAssign_Button').click(function () {
|
||||
showModeDialog();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
|
||||
|
||||
@@ -32,19 +32,25 @@ namespace Disco.Web.Areas.Config.Views.UserFlag
|
||||
using Disco.Services;
|
||||
using Disco.Services.Authorization;
|
||||
|
||||
#line 3 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 2 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 2 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 3 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
using Disco.Services.Users.UserFlags;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
using Disco.Services.Web;
|
||||
using Disco.Web;
|
||||
|
||||
#line 4 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
using Disco.Web.Areas.Config.Models.Shared;
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
using Disco.Web.Extensions;
|
||||
|
||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
|
||||
@@ -57,7 +63,7 @@ namespace Disco.Web.Areas.Config.Views.UserFlag
|
||||
public override void Execute()
|
||||
{
|
||||
|
||||
#line 4 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 5 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
Authorization.Require(Claims.Config.UserFlag.Show);
|
||||
|
||||
@@ -68,6 +74,10 @@ namespace Disco.Web.Areas.Config.Views.UserFlag
|
||||
var canBulkAssignment = Authorization.HasAll(Claims.User.Actions.AddFlags, Claims.User.Actions.RemoveFlags, Claims.User.ShowFlagAssignments);
|
||||
var canShowUsers = Model.CurrentAssignmentCount > 0 && Authorization.HasAll(Claims.User.Search, Claims.User.ShowFlagAssignments);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.UserFlag.UserDevicesLinkedGroup == null &&
|
||||
Model.UserFlag.UsersLinkedGroup == null;
|
||||
|
||||
Html.BundleDeferred("~/ClientScripts/Modules/Disco-PropertyChangeHelpers");
|
||||
|
||||
|
||||
@@ -77,7 +87,16 @@ WriteLiteral("\r\n<div");
|
||||
|
||||
WriteLiteral(" id=\"Config_UserFlags_Show\"");
|
||||
|
||||
WriteLiteral(" class=\"form\"");
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 1092), Tuple.Create("\"", 1151)
|
||||
, Tuple.Create(Tuple.Create("", 1100), Tuple.Create("form", 1100), true)
|
||||
|
||||
#line 21 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 1104), Tuple.Create<System.Object, System.Int32>(hideAdvanced ? " Config_HideAdvanced" : null
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 1104), false)
|
||||
);
|
||||
|
||||
WriteLiteral(" style=\"width: 550px\"");
|
||||
|
||||
@@ -90,7 +109,7 @@ WriteLiteral(">Id:\r\n </th>\r\n <td>\r\n");
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 22 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 27 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.DisplayFor(model => model.UserFlag.Id));
|
||||
|
||||
|
||||
@@ -100,49 +119,49 @@ WriteLiteral("\r\n </td>\r\n </tr>\r\n <tr>\r\n
|
||||
" </th>\r\n <td>");
|
||||
|
||||
|
||||
#line 28 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 33 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 29 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 34 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.EditorFor(model => model.UserFlag.Name));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 29 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 34 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 30 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 35 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxSave());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 30 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 35 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 31 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 36 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 31 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 36 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
@@ -157,7 +176,7 @@ WriteLiteral(">\r\n $(function () {\r\n
|
||||
" \'Invalid Name\',\r\n \'");
|
||||
|
||||
|
||||
#line 37 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 42 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.UpdateName(Model.UserFlag.Id)));
|
||||
|
||||
|
||||
@@ -167,7 +186,7 @@ WriteLiteral("\',\r\n \'FlagName\'\r\n
|
||||
" });\r\n </script>\r\n");
|
||||
|
||||
|
||||
#line 42 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 47 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -176,14 +195,14 @@ WriteLiteral("\',\r\n \'FlagName\'\r\n
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 45 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 50 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.UserFlag.Name);
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 45 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 50 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
@@ -194,49 +213,49 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
|
||||
" </th>\r\n <td>");
|
||||
|
||||
|
||||
#line 52 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 57 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 53 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 58 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.EditorFor(model => model.UserFlag.Description));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 53 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 58 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 54 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 59 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxSave());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 54 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 59 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 55 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 60 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 55 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 60 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
@@ -252,7 +271,7 @@ WriteLiteral(">\r\n $(function () {\r\n
|
||||
" \'");
|
||||
|
||||
|
||||
#line 61 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 66 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.UpdateDescription(Model.UserFlag.Id)));
|
||||
|
||||
|
||||
@@ -262,7 +281,7 @@ WriteLiteral("\',\r\n \'Description\'\r\n
|
||||
" });\r\n </script>\r\n");
|
||||
|
||||
|
||||
#line 66 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 71 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -273,13 +292,13 @@ WriteLiteral("\',\r\n \'Description\'\r\n
|
||||
WriteLiteral(" <pre>\r\n");
|
||||
|
||||
|
||||
#line 70 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 75 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 70 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 75 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (string.IsNullOrEmpty(Model.UserFlag.Description))
|
||||
{
|
||||
|
||||
@@ -293,7 +312,7 @@ WriteLiteral("<None>");
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
|
||||
#line 73 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 78 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -302,14 +321,14 @@ WriteLiteral("\r\n");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 76 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 81 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.UserFlag.Description.ToHtmlComment());
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 76 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 81 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
@@ -319,7 +338,7 @@ WriteLiteral("\r\n");
|
||||
WriteLiteral(" </pre>\r\n");
|
||||
|
||||
|
||||
#line 79 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 84 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +348,7 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
|
||||
" </th>\r\n <td>\r\n <div><strong>");
|
||||
|
||||
|
||||
#line 86 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 91 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.CurrentAssignmentCount);
|
||||
|
||||
|
||||
@@ -338,7 +357,7 @@ WriteLiteral(" </td>\r\n </tr>\r\n <tr>\r\n
|
||||
WriteLiteral(" user");
|
||||
|
||||
|
||||
#line 86 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 91 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.CurrentAssignmentCount != 1 ? "s" : null);
|
||||
|
||||
|
||||
@@ -347,7 +366,7 @@ WriteLiteral(" user");
|
||||
WriteLiteral(" currently assigned</strong></div>\r\n <div>");
|
||||
|
||||
|
||||
#line 87 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 92 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.TotalAssignmentCount);
|
||||
|
||||
|
||||
@@ -356,7 +375,7 @@ WriteLiteral(" currently assigned</strong></div>\r\n <div>");
|
||||
WriteLiteral(" total user historical assignment");
|
||||
|
||||
|
||||
#line 87 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 92 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.TotalAssignmentCount != 1 ? "s" : null);
|
||||
|
||||
|
||||
@@ -370,7 +389,7 @@ WriteLiteral(" id=\"Config_UserFlags_Icon\"");
|
||||
WriteLiteral(" data-icon=\"");
|
||||
|
||||
|
||||
#line 94 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 99 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.UserFlag.Icon);
|
||||
|
||||
|
||||
@@ -381,7 +400,7 @@ WriteLiteral("\"");
|
||||
WriteLiteral(" data-colour=\"");
|
||||
|
||||
|
||||
#line 94 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 99 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.UserFlag.IconColour);
|
||||
|
||||
|
||||
@@ -389,37 +408,37 @@ WriteLiteral(" data-colour=\"");
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 3815), Tuple.Create("\"", 3888)
|
||||
, Tuple.Create(Tuple.Create("", 3823), Tuple.Create("fa", 3823), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 3825), Tuple.Create("fa-", 3826), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4042), Tuple.Create("\"", 4115)
|
||||
, Tuple.Create(Tuple.Create("", 4050), Tuple.Create("fa", 4050), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4052), Tuple.Create("fa-", 4053), true)
|
||||
|
||||
#line 94 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 3829), Tuple.Create<System.Object, System.Int32>(Model.UserFlag.Icon
|
||||
#line 99 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4056), Tuple.Create<System.Object, System.Int32>(Model.UserFlag.Icon
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 3829), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 3851), Tuple.Create("fa-4x", 3852), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 3857), Tuple.Create("d-", 3858), true)
|
||||
, 4056), false)
|
||||
, Tuple.Create(Tuple.Create(" ", 4078), Tuple.Create("fa-4x", 4079), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4084), Tuple.Create("d-", 4085), true)
|
||||
|
||||
#line 94 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 3860), Tuple.Create<System.Object, System.Int32>(Model.UserFlag.IconColour
|
||||
#line 99 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4087), Tuple.Create<System.Object, System.Int32>(Model.UserFlag.IconColour
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 3860), false)
|
||||
, 4087), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 95 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 100 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 95 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 100 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
@@ -449,13 +468,13 @@ WriteLiteral(" class=\"icons\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 102 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 107 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 102 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 107 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
foreach (var icon in Model.Icons)
|
||||
{
|
||||
|
||||
@@ -467,7 +486,7 @@ WriteLiteral(" <i");
|
||||
WriteLiteral(" data-icon=\"");
|
||||
|
||||
|
||||
#line 104 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 109 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(icon.Key);
|
||||
|
||||
|
||||
@@ -475,32 +494,32 @@ WriteLiteral(" data-icon=\"");
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4453), Tuple.Create("\"", 4478)
|
||||
, Tuple.Create(Tuple.Create("", 4461), Tuple.Create("fa", 4461), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4463), Tuple.Create("fa-", 4464), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4680), Tuple.Create("\"", 4705)
|
||||
, Tuple.Create(Tuple.Create("", 4688), Tuple.Create("fa", 4688), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4690), Tuple.Create("fa-", 4691), true)
|
||||
|
||||
#line 104 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4467), Tuple.Create<System.Object, System.Int32>(icon.Key
|
||||
#line 109 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4694), Tuple.Create<System.Object, System.Int32>(icon.Key
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 4467), false)
|
||||
, 4694), false)
|
||||
);
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 4479), Tuple.Create("\"", 4498)
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 4706), Tuple.Create("\"", 4725)
|
||||
|
||||
#line 104 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4487), Tuple.Create<System.Object, System.Int32>(icon.Value
|
||||
#line 109 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4714), Tuple.Create<System.Object, System.Int32>(icon.Value
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 4487), false)
|
||||
, 4714), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 105 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 110 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -513,13 +532,13 @@ WriteLiteral(" class=\"colours\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 108 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 113 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 108 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 113 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
foreach (var colour in Model.ThemeColours)
|
||||
{
|
||||
|
||||
@@ -531,7 +550,7 @@ WriteLiteral(" <i");
|
||||
WriteLiteral(" data-colour=\"");
|
||||
|
||||
|
||||
#line 110 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 115 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(colour.Key);
|
||||
|
||||
|
||||
@@ -539,33 +558,33 @@ WriteLiteral(" data-colour=\"");
|
||||
#line hidden
|
||||
WriteLiteral("\"");
|
||||
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 4830), Tuple.Create("\"", 4866)
|
||||
, Tuple.Create(Tuple.Create("", 4838), Tuple.Create("fa", 4838), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4840), Tuple.Create("fa-square", 4841), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 4850), Tuple.Create("d-", 4851), true)
|
||||
WriteAttribute("class", Tuple.Create(" class=\"", 5057), Tuple.Create("\"", 5093)
|
||||
, Tuple.Create(Tuple.Create("", 5065), Tuple.Create("fa", 5065), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 5067), Tuple.Create("fa-square", 5068), true)
|
||||
, Tuple.Create(Tuple.Create(" ", 5077), Tuple.Create("d-", 5078), true)
|
||||
|
||||
#line 110 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4853), Tuple.Create<System.Object, System.Int32>(colour.Key
|
||||
#line 115 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 5080), Tuple.Create<System.Object, System.Int32>(colour.Key
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 4853), false)
|
||||
, 5080), false)
|
||||
);
|
||||
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 4867), Tuple.Create("\"", 4888)
|
||||
WriteAttribute("title", Tuple.Create(" title=\"", 5094), Tuple.Create("\"", 5115)
|
||||
|
||||
#line 110 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 4875), Tuple.Create<System.Object, System.Int32>(colour.Value
|
||||
#line 115 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
, Tuple.Create(Tuple.Create("", 5102), Tuple.Create<System.Object, System.Int32>(colour.Value
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
, 4875), false)
|
||||
, 5102), false)
|
||||
);
|
||||
|
||||
WriteLiteral("></i>\r\n");
|
||||
|
||||
|
||||
#line 111 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 116 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -612,7 +631,7 @@ WriteLiteral(" </div>\r\n
|
||||
"save() {\r\n var url = \'");
|
||||
|
||||
|
||||
#line 171 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 176 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.UpdateIconAndColour(id: Model.UserFlag.Id, redirect: true)));
|
||||
|
||||
|
||||
@@ -643,16 +662,137 @@ WriteLiteral(@"',
|
||||
");
|
||||
|
||||
|
||||
#line 193 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 198 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n </table>\r\n</div>\r\n");
|
||||
WriteLiteral(" </td>\r\n </tr>\r\n");
|
||||
|
||||
|
||||
#line 198 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 201 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 201 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (hideAdvanced)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <tr>\r\n <td");
|
||||
|
||||
WriteLiteral(" colspan=\"2\"");
|
||||
|
||||
WriteLiteral(" style=\"text-align: right;\"");
|
||||
|
||||
WriteLiteral(">\r\n <button");
|
||||
|
||||
WriteLiteral(" id=\"Config_HideAdvanced_Show\"");
|
||||
|
||||
WriteLiteral(" class=\"button small\"");
|
||||
|
||||
WriteLiteral(@">Show Advanced Options</button>
|
||||
<script>
|
||||
$(function () {
|
||||
$('#Config_HideAdvanced_Show').click(function () {
|
||||
var $this = $(this);
|
||||
$this.closest('.Config_HideAdvanced').removeClass('Config_HideAdvanced');
|
||||
$this.closest('tr').remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</td>
|
||||
</tr>
|
||||
");
|
||||
|
||||
|
||||
#line 217 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" <tr");
|
||||
|
||||
WriteLiteral(" class=\"Config_HideAdvanced_Item\"");
|
||||
|
||||
WriteLiteral(">\r\n <th>Linked Groups:\r\n </th>\r\n <td>\r\n " +
|
||||
" <div>\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 223 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = UserFlagUsersManagedGroup.GetCategoryDescription(Model.UserFlag),
|
||||
Description = UserFlagUsersManagedGroup.GetDescription(Model.UserFlag),
|
||||
ManagedGroup = Model.UsersLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUsersLinkedGroup(Model.UserFlag.Id, redirect: true))
|
||||
}));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 231 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.Partial(MVC.Config.Shared.Views.LinkedGroupInstance, new LinkedGroupModel()
|
||||
{
|
||||
CanConfigure = canConfig,
|
||||
CategoryDescription = UserFlagUserDevicesManagedGroup.GetCategoryDescription(Model.UserFlag),
|
||||
Description = UserFlagUserDevicesManagedGroup.GetDescription(Model.UserFlag),
|
||||
ManagedGroup = Model.UserDevicesLinkedGroup,
|
||||
UpdateUrl = Url.Action(MVC.API.UserFlag.UpdateAssignedUserDevicesLinkedGroup(Model.UserFlag.Id, redirect: true))
|
||||
}));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\r\n");
|
||||
|
||||
|
||||
#line 239 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 239 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canConfig)
|
||||
{
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 241 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.Partial(MVC.Config.Shared.Views.LinkedGroupShared));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 241 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(" </div>\r\n </td>\r\n </tr>\r\n </table>\r\n</div>\r\n");
|
||||
|
||||
|
||||
#line 248 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canBulkAssignment || canDelete || canShowUsers)
|
||||
{
|
||||
|
||||
@@ -666,13 +806,13 @@ WriteLiteral(" class=\"actionBar\"");
|
||||
WriteLiteral(">\r\n");
|
||||
|
||||
|
||||
#line 201 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 251 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 201 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 251 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canBulkAssignment)
|
||||
{
|
||||
|
||||
@@ -758,7 +898,7 @@ WriteLiteral(">\r\n user6<br />\r\n
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 234 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 284 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName);
|
||||
|
||||
|
||||
@@ -771,7 +911,7 @@ WriteLiteral(" class=\"code\"");
|
||||
WriteLiteral(">user6,smi0099,");
|
||||
|
||||
|
||||
#line 236 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 286 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName);
|
||||
|
||||
|
||||
@@ -784,7 +924,7 @@ WriteLiteral(" class=\"code\"");
|
||||
WriteLiteral(">user6;smi0099;");
|
||||
|
||||
|
||||
#line 237 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 287 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(ActiveDirectory.Context.PrimaryDomain.NetBiosName);
|
||||
|
||||
|
||||
@@ -814,8 +954,6 @@ WriteLiteral(" id=\"Config_UserFlags_BulkAssign_AssignDialog_UserIds\"");
|
||||
|
||||
WriteLiteral(" name=\"UserIds\"");
|
||||
|
||||
WriteLiteral(" data-val=\"true\"");
|
||||
|
||||
WriteLiteral("></textarea>\r\n <h4>Comments:</h4>\r\n <textar" +
|
||||
"ea");
|
||||
|
||||
@@ -861,64 +999,64 @@ WriteLiteral(" <script>\r\n $(function () {\r\n
|
||||
"\').attr(\'action\', \'");
|
||||
|
||||
|
||||
#line 304 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 354 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, true)));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral("\');\r\n\r\n assignDialog.addClass(\'loading\');\r\n " +
|
||||
" $.getJSON(\'");
|
||||
WriteLiteral("\');\r\n\r\n assignDialog.addClass(\'loading\');\r\n " +
|
||||
" $.getJSON(\'");
|
||||
|
||||
|
||||
#line 307 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.AssignedUsers(Model.UserFlag.Id)));
|
||||
#line 357 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.AssignedUsers(Model.UserFlag.Id)));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"', function (response, result) {
|
||||
assignDialog.removeClass('loading');
|
||||
assignDialog.removeClass('loading');
|
||||
|
||||
if (result != 'success') {
|
||||
alert('Unable to load current assignments:\n' + response);
|
||||
assignDialog.dialog('close');
|
||||
} else {
|
||||
if (!!response) {
|
||||
assignUserIds.val(response.join('\n'));
|
||||
} else {
|
||||
assignUserIds.val('');
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result != 'success') {
|
||||
alert('Unable to load current assignments:\n' + response);
|
||||
assignDialog.dialog('close');
|
||||
} else {
|
||||
if (!!response) {
|
||||
assignUserIds.val(response.join('\n'));
|
||||
} else {
|
||||
assignUserIds.val('');
|
||||
}
|
||||
}
|
||||
else // Assume Add
|
||||
{
|
||||
assignUserIds.closest('form').attr('action', '");
|
||||
});
|
||||
}
|
||||
else // Assume Add
|
||||
{
|
||||
assignUserIds.closest('form').attr('action', '");
|
||||
|
||||
|
||||
#line 324 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, false)));
|
||||
#line 374 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.UserFlag.BulkAssignUsers(Model.UserFlag.Id, false)));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
WriteLiteral(@"');
|
||||
}
|
||||
}
|
||||
|
||||
assignDialog.dialog('open');
|
||||
}
|
||||
assignDialog.dialog('open');
|
||||
}
|
||||
|
||||
$('#Config_UserFlags_BulkAssign_Button').click(function () {
|
||||
showModeDialog();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
$('#Config_UserFlags_BulkAssign_Button').click(function () {
|
||||
showModeDialog();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
");
|
||||
|
||||
|
||||
#line 336 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 386 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -927,13 +1065,13 @@ WriteLiteral(@"');
|
||||
WriteLiteral("\r\n\r\n\r\n");
|
||||
|
||||
|
||||
#line 340 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 390 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 340 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 390 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canDelete)
|
||||
{
|
||||
|
||||
@@ -941,14 +1079,14 @@ WriteLiteral("\r\n\r\n\r\n");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 342 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 392 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.ActionLinkButton("Delete", MVC.API.UserFlag.Delete(Model.UserFlag.Id, true), "Config_UserFlags_Actions_Delete_Button"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 342 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 392 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
|
||||
@@ -968,13 +1106,13 @@ WriteLiteral("></i>\r\n This item will be permanently deleted
|
||||
"covered.<br />\r\n <br />\r\n");
|
||||
|
||||
|
||||
#line 348 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 398 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 348 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 398 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (Model.CurrentAssignmentCount > 0)
|
||||
{
|
||||
|
||||
@@ -984,7 +1122,7 @@ WriteLiteral("></i>\r\n This item will be permanently deleted
|
||||
WriteLiteral(" <strong>");
|
||||
|
||||
|
||||
#line 350 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 400 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.CurrentAssignmentCount);
|
||||
|
||||
|
||||
@@ -993,7 +1131,7 @@ WriteLiteral(" <strong>");
|
||||
WriteLiteral(" user");
|
||||
|
||||
|
||||
#line 350 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 400 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Model.CurrentAssignmentCount != 1 ? "s are" : " is");
|
||||
|
||||
|
||||
@@ -1006,7 +1144,7 @@ WriteLiteral(" <br />\r\n");
|
||||
WriteLiteral(" <br />\r\n");
|
||||
|
||||
|
||||
#line 353 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 403 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1049,7 +1187,7 @@ WriteLiteral(@">
|
||||
");
|
||||
|
||||
|
||||
#line 385 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 435 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
|
||||
@@ -1058,7 +1196,7 @@ WriteLiteral(@">
|
||||
WriteLiteral(" ");
|
||||
|
||||
|
||||
#line 386 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 436 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
if (canShowUsers)
|
||||
{
|
||||
|
||||
@@ -1066,14 +1204,14 @@ WriteLiteral(" ");
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 388 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 438 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
Write(Html.ActionLinkButton(string.Format("Show {0} user{1}", Model.CurrentAssignmentCount, (Model.CurrentAssignmentCount == 1 ? null : "s")), MVC.Search.Query(Model.UserFlag.Id.ToString(), "UserFlag"), "Config_UserFlags_Actions_ShowUsers_Button"));
|
||||
|
||||
|
||||
#line default
|
||||
#line hidden
|
||||
|
||||
#line 388 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 438 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
|
||||
}
|
||||
|
||||
@@ -1083,7 +1221,7 @@ WriteLiteral(" ");
|
||||
WriteLiteral(" </div>\r\n");
|
||||
|
||||
|
||||
#line 391 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
#line 441 "..\..\Areas\Config\Views\UserFlag\Show.cshtml"
|
||||
}
|
||||
|
||||
#line default
|
||||
|
||||
@@ -651,9 +651,9 @@ Webcam.init();
|
||||
|
||||
xhr.open("POST", self.uploadUrl, true);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status !== 200) {
|
||||
alert('Error Uploading [' + fileName + ']: ' + xhr.responseText);
|
||||
alert('Error Uploading [' + fileName + ']: ' + xhr.statusText);
|
||||
}
|
||||
progress.slideUp(400, function () {
|
||||
progress.remove();
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2
-2
@@ -250,9 +250,9 @@
|
||||
|
||||
xhr.open("POST", self.uploadUrl, true);
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4 && xhr.status === 200) {
|
||||
if (xhr.readyState === 4) {
|
||||
if (xhr.status !== 200) {
|
||||
alert('Error Uploading [' + fileName + ']: ' + xhr.responseText);
|
||||
alert('Error Uploading [' + fileName + ']: ' + xhr.statusText);
|
||||
}
|
||||
progress.slideUp(400, function () {
|
||||
progress.remove();
|
||||
|
||||
@@ -2095,6 +2095,13 @@ input:-moz-placeholder {
|
||||
font-weight: bold;
|
||||
}*/
|
||||
.ui-dialog {
|
||||
position: fixed;
|
||||
overflow: visible;
|
||||
padding: 0;
|
||||
border-color: #333333;
|
||||
background: #fcfcfc;
|
||||
box-shadow: rgba(20, 20, 20, 0.7) 0px 0px 50px;
|
||||
top: 50px !important;
|
||||
animation-name: ui-dialog-show;
|
||||
-webkit-animation-name: ui-dialog-show;
|
||||
animation-duration: .2s;
|
||||
@@ -2102,6 +2109,18 @@ input:-moz-placeholder {
|
||||
animation-timing-function: ease-in-out;
|
||||
-webkit-animation-timing-function: ease-in-out;
|
||||
}
|
||||
.ui-dialog .ui-widget-header {
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom-color: #d1d1d1;
|
||||
background: #333333;
|
||||
color: #fff;
|
||||
font-size: 1.1em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
padding: .6em 1em;
|
||||
}
|
||||
@keyframes ui-dialog-show {
|
||||
0% {
|
||||
transform: translateY(-30px);
|
||||
@@ -2149,25 +2168,6 @@ input:-moz-placeholder {
|
||||
.page .dialog {
|
||||
display: none;
|
||||
}
|
||||
.ui-dialog {
|
||||
padding: 0;
|
||||
border-color: #333333;
|
||||
background: #fcfcfc;
|
||||
box-shadow: rgba(20, 20, 20, 0.7) 0px 0px 50px;
|
||||
top: 50px !important;
|
||||
}
|
||||
.ui-dialog .ui-widget-header {
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-bottom-color: #d1d1d1;
|
||||
background: #333333;
|
||||
color: #fff;
|
||||
font-size: 1.1em;
|
||||
font-weight: normal;
|
||||
text-transform: uppercase;
|
||||
padding: .6em 1em;
|
||||
}
|
||||
body .ui-tooltip {
|
||||
border-width: 1px;
|
||||
-webkit-box-shadow: none;
|
||||
@@ -4111,7 +4111,7 @@ a.button {
|
||||
border: 1px solid #1a5f95;
|
||||
background: #1e6dab;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
@@ -4753,6 +4753,43 @@ div.form > table table.sub > tbody > tr > th.name {
|
||||
border-right: none;
|
||||
padding-right: 0;
|
||||
}
|
||||
div.infoBox {
|
||||
margin: 0.4em 0;
|
||||
padding: 0.4em;
|
||||
border: 1px solid #fff397;
|
||||
background-color: #fffef7;
|
||||
}
|
||||
div.infoBox i {
|
||||
color: #1e6dab;
|
||||
}
|
||||
div.infoBox.alert {
|
||||
border: 1px solid #fa6800;
|
||||
background-color: #fff9f5;
|
||||
color: #333333;
|
||||
}
|
||||
div.infoBox.alert i {
|
||||
color: #fa6800;
|
||||
}
|
||||
div.infoBox.error {
|
||||
border: 1px solid #e51400;
|
||||
background-color: #fffaf9;
|
||||
color: #e51400;
|
||||
}
|
||||
div.infoBox.error i {
|
||||
color: #e51400;
|
||||
}
|
||||
div.infoBox p {
|
||||
line-height: 1.2em;
|
||||
}
|
||||
p.fa-p {
|
||||
text-indent: -1.48em;
|
||||
margin-left: 1.48em;
|
||||
}
|
||||
p.fa-p > i:first-child {
|
||||
text-indent: 0;
|
||||
width: 1.28em;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
div.disco-attachmentUpload-dropTarget {
|
||||
display: none;
|
||||
}
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user