GIT: perform LF normalization
This commit is contained in:
@@ -1,397 +1,397 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.BI.DeviceBI;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectory
|
||||
{
|
||||
public static ActiveDirectoryMachineAccount GetMachineAccount(string ComputerName, System.Guid? UUIDNetbootGUID = null, System.Guid? MacAddressNetbootGUID = null, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ComputerName))
|
||||
throw new System.ArgumentException("Invalid Computer Name - Empty", "ComputerName");
|
||||
if (ComputerName.Contains("\\"))
|
||||
ComputerName = ComputerName.Substring(checked(ComputerName.IndexOf("\\") + 1));
|
||||
if (ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name - Length > 24", "ComputerName");
|
||||
string sAMAccountName = ComputerName;
|
||||
if (!sAMAccountName.EndsWith("$"))
|
||||
sAMAccountName = string.Format("{0}$", sAMAccountName);
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = new List<string> { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
||||
loadProperties.AddRange(AdditionalProperties);
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
|
||||
if (UUIDNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MacAddressNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static ActiveDirectoryMachineAccount DirectorySearchResultToMachineAccount(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string sAMAccountName = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
||||
|
||||
var dNSNameProperty = result.Properties["dNSHostName"];
|
||||
string dNSName = null;
|
||||
if (dNSNameProperty.Count > 0)
|
||||
dNSName = dNSNameProperty[0].ToString();
|
||||
else
|
||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
bool isCriticalSystemObject = (bool)result.Properties["isCriticalSystemObject"][0];
|
||||
|
||||
System.Guid netbootGUIDResult = default(System.Guid);
|
||||
ResultPropertyValueCollection netbootGUIDProp = result.Properties["netbootGUID"];
|
||||
if (netbootGUIDProp.Count > 0)
|
||||
{
|
||||
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryMachineAccount
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
sAMAccountName = sAMAccountName,
|
||||
ObjectSid = objectSid,
|
||||
NetbootGUID = netbootGUIDResult,
|
||||
Path = result.Path,
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
DnsName = dNSName,
|
||||
IsCriticalSystemObject = isCriticalSystemObject,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
private static ActiveDirectoryUserAccount SearchResultToActiveDirectoryUserAccount(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string username = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
||||
|
||||
ResultPropertyValueCollection displayNameProp = result.Properties["displayName"];
|
||||
string displayName = username;
|
||||
if (displayNameProp.Count > 0)
|
||||
displayName = displayNameProp[0].ToString();
|
||||
string surname = null;
|
||||
ResultPropertyValueCollection surnameProp = result.Properties["sn"];
|
||||
if (surnameProp.Count > 0)
|
||||
surname = surnameProp[0].ToString();
|
||||
string givenName = null;
|
||||
ResultPropertyValueCollection givenNameProp = result.Properties["givenName"];
|
||||
if (givenNameProp.Count > 0)
|
||||
givenName = givenNameProp[0].ToString();
|
||||
string email = null;
|
||||
ResultPropertyValueCollection emailProp = result.Properties["mail"];
|
||||
if (emailProp.Count > 0)
|
||||
email = emailProp[0].ToString();
|
||||
string phone = null;
|
||||
ResultPropertyValueCollection phoneProp = result.Properties["telephoneNumber"];
|
||||
if (phoneProp.Count > 0)
|
||||
phone = phoneProp[0].ToString();
|
||||
|
||||
IEnumerable<string> groupCNs = result.Properties["memberOf"].Cast<string>();
|
||||
List<string> groups = ActiveDirectoryCachedGroups.GetGroups(groupCNs).Select(g => g.ToLower()).ToList();
|
||||
|
||||
//foreach (string groupCN in result.Properties["memberOf"])
|
||||
//{
|
||||
// Removed 2012-11-30 G# - Moved to Recursive Cache
|
||||
//var groupCNlower = groupCN.ToLower();
|
||||
//if (groupCNlower.StartsWith("cn="))
|
||||
// groups.Add(groupCNlower.Substring(3, groupCNlower.IndexOf(",") - 3));
|
||||
// End Removed 2012-11-30 G#
|
||||
//}
|
||||
|
||||
string type = null;
|
||||
if (groups.Contains("domain admins") || groups.Contains("disco admins"))
|
||||
{
|
||||
type = "Admin";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (groups.Contains("staff"))
|
||||
{
|
||||
type = "Staff";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (groups.Contains("students"))
|
||||
{
|
||||
type = "Student";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryUserAccount
|
||||
{
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
Name = name,
|
||||
Surname = surname,
|
||||
GivenName = givenName,
|
||||
Email = email,
|
||||
Phone = phone,
|
||||
DistinguishedName = distinguishedName,
|
||||
sAMAccountName = username,
|
||||
DisplayName = displayName,
|
||||
ObjectSid = objectSid,
|
||||
Type = type,
|
||||
Path = result.Path,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
public static ActiveDirectoryUserAccount GetUserAccount(string Username, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Username))
|
||||
throw new System.ArgumentException("Invalid User Account", "Username");
|
||||
string sAMAccountName = Username;
|
||||
if (sAMAccountName.Contains("\\"))
|
||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = new List<string> {
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"displayName",
|
||||
"sn",
|
||||
"givenName",
|
||||
"memberOf",
|
||||
"mail",
|
||||
"telephoneNumber"
|
||||
};
|
||||
loadProperties.AddRange(AdditionalProperties);
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=user)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
return ActiveDirectory.SearchResultToActiveDirectoryUserAccount(dResult, AdditionalProperties);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static string OfflineDomainJoinProvision(ref ActiveDirectoryMachineAccount ExistingAccount, string ComputerName, string OrganisationalUnit = null, string EnrolSessionId = null)
|
||||
{
|
||||
if (ExistingAccount != null && ExistingAccount.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", ExistingAccount.DistinguishedName));
|
||||
|
||||
string DJoinResult = null;
|
||||
if (string.IsNullOrWhiteSpace(ComputerName) || ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
||||
|
||||
// Added 2012-10-25 G#
|
||||
// Ensure Specified OU Exists
|
||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
||||
{
|
||||
var ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
try
|
||||
{
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
if (ou == null)
|
||||
{
|
||||
throw new Exception("OU's Directory Entry couldn't be found");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", ouPath), "OrganisationalUnit", ex);
|
||||
}
|
||||
}
|
||||
// End Added 2012-10-25 G#
|
||||
|
||||
// Delete Existing
|
||||
if (ExistingAccount != null)
|
||||
ExistingAccount.DeleteAccount();
|
||||
|
||||
string tempFileName = System.IO.Path.GetTempFileName();
|
||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0},{1}\"", OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName) : string.Empty;
|
||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
||||
ActiveDirectoryHelpers.DefaultDomainName,
|
||||
ActiveDirectoryHelpers.DefaultDomainPDCName,
|
||||
ComputerName,
|
||||
argumentOU,
|
||||
tempFileName
|
||||
);
|
||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
LoadUserProfile = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, string.Format("{0} {1}{2}", "DJOIN.EXE", arguments, System.Environment.NewLine));
|
||||
}
|
||||
|
||||
string stdOutput;
|
||||
string stdError;
|
||||
using (Process commandProc = Process.Start(commandStarter))
|
||||
{
|
||||
commandProc.WaitForExit(20000);
|
||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
||||
stdError = commandProc.StandardError.ReadToEnd();
|
||||
}
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdOutput + System.Environment.NewLine);
|
||||
if (!string.IsNullOrWhiteSpace(stdError))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdError + System.Environment.NewLine);
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(tempFileName))
|
||||
{
|
||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
||||
System.IO.File.Delete(tempFileName);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
||||
ExistingAccount = ActiveDirectory.GetMachineAccount(ComputerName);
|
||||
return DJoinResult;
|
||||
}
|
||||
|
||||
public static List<ActiveDirectoryUserAccount> SearchUsers(string term)
|
||||
{
|
||||
List<ActiveDirectoryUserAccount> users = new List<ActiveDirectoryUserAccount>();
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
||||
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectClass=User)(objectCategory=Person)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", term), new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"displayName",
|
||||
"sn",
|
||||
"givenName",
|
||||
"memberOf",
|
||||
"mail",
|
||||
"telephoneNumber"
|
||||
}, SearchScope.Subtree))
|
||||
{
|
||||
searcher.SizeLimit = 30;
|
||||
SearchResultCollection results = searcher.FindAll();
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
users.Add(ActiveDirectory.SearchResultToActiveDirectoryUserAccount(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
public static List<ActiveDirectoryOrganisationalUnit> GetOrganisationalUnitStructure()
|
||||
{
|
||||
ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Children = new System.Collections.Generic.List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref DomainOUs, entry);
|
||||
}
|
||||
return DomainOUs.Children;
|
||||
}
|
||||
private static void GetOrganisationalUnitStructure_Recursive(ref ActiveDirectoryOrganisationalUnit ParentOU, DirectoryEntry Container)
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName"
|
||||
}, SearchScope.OneLevel))
|
||||
{
|
||||
using (SearchResultCollection results = searcher.FindAll())
|
||||
{
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
string i = result.Properties["name"][0].ToString();
|
||||
string dn = result.Properties["distinguishedName"][0].ToString();
|
||||
ActiveDirectoryOrganisationalUnit ChildOU = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Name = i,
|
||||
Path = dn.Substring(0, dn.IndexOf(",DC=")),
|
||||
Children = new List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry());
|
||||
if (ChildOU.Children.Count == 0)
|
||||
ChildOU.Children = null;
|
||||
ParentOU.Children.Add(ChildOU);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.BI.DeviceBI;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectory
|
||||
{
|
||||
public static ActiveDirectoryMachineAccount GetMachineAccount(string ComputerName, System.Guid? UUIDNetbootGUID = null, System.Guid? MacAddressNetbootGUID = null, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ComputerName))
|
||||
throw new System.ArgumentException("Invalid Computer Name - Empty", "ComputerName");
|
||||
if (ComputerName.Contains("\\"))
|
||||
ComputerName = ComputerName.Substring(checked(ComputerName.IndexOf("\\") + 1));
|
||||
if (ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name - Length > 24", "ComputerName");
|
||||
string sAMAccountName = ComputerName;
|
||||
if (!sAMAccountName.EndsWith("$"))
|
||||
sAMAccountName = string.Format("{0}$", sAMAccountName);
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = new List<string> { "name", "distinguishedName", "sAMAccountName", "objectSid", "dNSHostName", "netbootGUID", "isCriticalSystemObject" };
|
||||
loadProperties.AddRange(AdditionalProperties);
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
|
||||
if (UUIDNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(UUIDNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (MacAddressNetbootGUID.HasValue)
|
||||
{
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=computer)(netbootGUID={0}))", ActiveDirectoryHelpers.FormatGuidForLdapQuery(MacAddressNetbootGUID.Value)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
{
|
||||
return ActiveDirectory.DirectorySearchResultToMachineAccount(dResult, AdditionalProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static ActiveDirectoryMachineAccount DirectorySearchResultToMachineAccount(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string sAMAccountName = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
||||
|
||||
var dNSNameProperty = result.Properties["dNSHostName"];
|
||||
string dNSName = null;
|
||||
if (dNSNameProperty.Count > 0)
|
||||
dNSName = dNSNameProperty[0].ToString();
|
||||
else
|
||||
dNSName = string.Format("{0}.{1}", sAMAccountName.TrimEnd('$'), ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
bool isCriticalSystemObject = (bool)result.Properties["isCriticalSystemObject"][0];
|
||||
|
||||
System.Guid netbootGUIDResult = default(System.Guid);
|
||||
ResultPropertyValueCollection netbootGUIDProp = result.Properties["netbootGUID"];
|
||||
if (netbootGUIDProp.Count > 0)
|
||||
{
|
||||
netbootGUIDResult = new System.Guid((byte[])netbootGUIDProp[0]);
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryMachineAccount
|
||||
{
|
||||
Name = name,
|
||||
DistinguishedName = distinguishedName,
|
||||
sAMAccountName = sAMAccountName,
|
||||
ObjectSid = objectSid,
|
||||
NetbootGUID = netbootGUIDResult,
|
||||
Path = result.Path,
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
DnsName = dNSName,
|
||||
IsCriticalSystemObject = isCriticalSystemObject,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
private static ActiveDirectoryUserAccount SearchResultToActiveDirectoryUserAccount(SearchResult result, params string[] AdditionalProperties)
|
||||
{
|
||||
string name = result.Properties["name"][0].ToString();
|
||||
string username = result.Properties["sAMAccountName"][0].ToString();
|
||||
string distinguishedName = result.Properties["distinguishedName"][0].ToString();
|
||||
string objectSid = ActiveDirectoryHelpers.ConvertBytesToSIDString((byte[])result.Properties["objectSid"][0]);
|
||||
|
||||
ResultPropertyValueCollection displayNameProp = result.Properties["displayName"];
|
||||
string displayName = username;
|
||||
if (displayNameProp.Count > 0)
|
||||
displayName = displayNameProp[0].ToString();
|
||||
string surname = null;
|
||||
ResultPropertyValueCollection surnameProp = result.Properties["sn"];
|
||||
if (surnameProp.Count > 0)
|
||||
surname = surnameProp[0].ToString();
|
||||
string givenName = null;
|
||||
ResultPropertyValueCollection givenNameProp = result.Properties["givenName"];
|
||||
if (givenNameProp.Count > 0)
|
||||
givenName = givenNameProp[0].ToString();
|
||||
string email = null;
|
||||
ResultPropertyValueCollection emailProp = result.Properties["mail"];
|
||||
if (emailProp.Count > 0)
|
||||
email = emailProp[0].ToString();
|
||||
string phone = null;
|
||||
ResultPropertyValueCollection phoneProp = result.Properties["telephoneNumber"];
|
||||
if (phoneProp.Count > 0)
|
||||
phone = phoneProp[0].ToString();
|
||||
|
||||
IEnumerable<string> groupCNs = result.Properties["memberOf"].Cast<string>();
|
||||
List<string> groups = ActiveDirectoryCachedGroups.GetGroups(groupCNs).Select(g => g.ToLower()).ToList();
|
||||
|
||||
//foreach (string groupCN in result.Properties["memberOf"])
|
||||
//{
|
||||
// Removed 2012-11-30 G# - Moved to Recursive Cache
|
||||
//var groupCNlower = groupCN.ToLower();
|
||||
//if (groupCNlower.StartsWith("cn="))
|
||||
// groups.Add(groupCNlower.Substring(3, groupCNlower.IndexOf(",") - 3));
|
||||
// End Removed 2012-11-30 G#
|
||||
//}
|
||||
|
||||
string type = null;
|
||||
if (groups.Contains("domain admins") || groups.Contains("disco admins"))
|
||||
{
|
||||
type = "Admin";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (groups.Contains("staff"))
|
||||
{
|
||||
type = "Staff";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (groups.Contains("students"))
|
||||
{
|
||||
type = "Student";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Additional Properties
|
||||
Dictionary<string, object[]> additionalProperties = new Dictionary<string, object[]>();
|
||||
foreach (string propertyName in AdditionalProperties)
|
||||
{
|
||||
var property = result.Properties[propertyName];
|
||||
var propertyValues = new List<object>();
|
||||
for (int index = 0; index < property.Count; index++)
|
||||
propertyValues.Add(property[index]);
|
||||
additionalProperties.Add(propertyName, propertyValues.ToArray());
|
||||
}
|
||||
|
||||
return new ActiveDirectoryUserAccount
|
||||
{
|
||||
Domain = ActiveDirectoryHelpers.DefaultDomainNetBiosName,
|
||||
Name = name,
|
||||
Surname = surname,
|
||||
GivenName = givenName,
|
||||
Email = email,
|
||||
Phone = phone,
|
||||
DistinguishedName = distinguishedName,
|
||||
sAMAccountName = username,
|
||||
DisplayName = displayName,
|
||||
ObjectSid = objectSid,
|
||||
Type = type,
|
||||
Path = result.Path,
|
||||
LoadedProperties = additionalProperties
|
||||
};
|
||||
}
|
||||
public static ActiveDirectoryUserAccount GetUserAccount(string Username, params string[] AdditionalProperties)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Username))
|
||||
throw new System.ArgumentException("Invalid User Account", "Username");
|
||||
string sAMAccountName = Username;
|
||||
if (sAMAccountName.Contains("\\"))
|
||||
sAMAccountName = sAMAccountName.Substring(checked(sAMAccountName.IndexOf("\\") + 1));
|
||||
|
||||
using (DirectoryEntry dRootEntry = ActiveDirectoryHelpers.DefaultLdapRoot)
|
||||
{
|
||||
var loadProperties = new List<string> {
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"displayName",
|
||||
"sn",
|
||||
"givenName",
|
||||
"memberOf",
|
||||
"mail",
|
||||
"telephoneNumber"
|
||||
};
|
||||
loadProperties.AddRange(AdditionalProperties);
|
||||
using (DirectorySearcher dSearcher = new DirectorySearcher(dRootEntry, string.Format("(&(objectClass=user)(sAMAccountName={0}))", ActiveDirectoryHelpers.EscapeLdapQuery(sAMAccountName)), loadProperties.ToArray(), SearchScope.Subtree))
|
||||
{
|
||||
SearchResult dResult = dSearcher.FindOne();
|
||||
if (dResult != null)
|
||||
return ActiveDirectory.SearchResultToActiveDirectoryUserAccount(dResult, AdditionalProperties);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static string OfflineDomainJoinProvision(ref ActiveDirectoryMachineAccount ExistingAccount, string ComputerName, string OrganisationalUnit = null, string EnrolSessionId = null)
|
||||
{
|
||||
if (ExistingAccount != null && ExistingAccount.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", ExistingAccount.DistinguishedName));
|
||||
|
||||
string DJoinResult = null;
|
||||
if (string.IsNullOrWhiteSpace(ComputerName) || ComputerName.Length > 24)
|
||||
throw new System.ArgumentException("Invalid Computer Name; > 0 and <= 24", "ComputerName");
|
||||
|
||||
// Added 2012-10-25 G#
|
||||
// Ensure Specified OU Exists
|
||||
if (!string.IsNullOrEmpty(OrganisationalUnit))
|
||||
{
|
||||
var ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
try
|
||||
{
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
if (ou == null)
|
||||
{
|
||||
throw new Exception("OU's Directory Entry couldn't be found");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(string.Format("An error occurred while trying to locate the specified OU: {0}", ouPath), "OrganisationalUnit", ex);
|
||||
}
|
||||
}
|
||||
// End Added 2012-10-25 G#
|
||||
|
||||
// Delete Existing
|
||||
if (ExistingAccount != null)
|
||||
ExistingAccount.DeleteAccount();
|
||||
|
||||
string tempFileName = System.IO.Path.GetTempFileName();
|
||||
string argumentOU = (!string.IsNullOrWhiteSpace(OrganisationalUnit)) ? string.Format(" /MACHINEOU \"{0},{1}\"", OrganisationalUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName) : string.Empty;
|
||||
string arguments = string.Format("/PROVISION /DOMAIN \"{0}\" /DCNAME \"{1}\" /MACHINE \"{2}\"{3} /REUSE /SAVEFILE \"{4}\"",
|
||||
ActiveDirectoryHelpers.DefaultDomainName,
|
||||
ActiveDirectoryHelpers.DefaultDomainPDCName,
|
||||
ComputerName,
|
||||
argumentOU,
|
||||
tempFileName
|
||||
);
|
||||
ProcessStartInfo commandStarter = new ProcessStartInfo("DJOIN.EXE", arguments)
|
||||
{
|
||||
CreateNoWindow = true,
|
||||
ErrorDialog = false,
|
||||
LoadUserProfile = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false
|
||||
};
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, string.Format("{0} {1}{2}", "DJOIN.EXE", arguments, System.Environment.NewLine));
|
||||
}
|
||||
|
||||
string stdOutput;
|
||||
string stdError;
|
||||
using (Process commandProc = Process.Start(commandStarter))
|
||||
{
|
||||
commandProc.WaitForExit(20000);
|
||||
stdOutput = commandProc.StandardOutput.ReadToEnd();
|
||||
stdError = commandProc.StandardError.ReadToEnd();
|
||||
}
|
||||
if (EnrolSessionId != null)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(stdOutput))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdOutput + System.Environment.NewLine);
|
||||
if (!string.IsNullOrWhiteSpace(stdError))
|
||||
EnrolmentLog.LogSessionDiagnosticInformation(EnrolSessionId, stdError + System.Environment.NewLine);
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(tempFileName))
|
||||
{
|
||||
DJoinResult = System.Convert.ToBase64String(System.IO.File.ReadAllBytes(tempFileName));
|
||||
System.IO.File.Delete(tempFileName);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(DJoinResult))
|
||||
throw new System.InvalidOperationException(string.Format("Domain Join Unsuccessful{0}Error: {1}{0}Output: {2}", System.Environment.NewLine, stdError, stdOutput));
|
||||
ExistingAccount = ActiveDirectory.GetMachineAccount(ComputerName);
|
||||
return DJoinResult;
|
||||
}
|
||||
|
||||
public static List<ActiveDirectoryUserAccount> SearchUsers(string term)
|
||||
{
|
||||
List<ActiveDirectoryUserAccount> users = new List<ActiveDirectoryUserAccount>();
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
string defaultNetBiosDomainName = ActiveDirectoryHelpers.DefaultDomainNetBiosName;
|
||||
term = ActiveDirectoryHelpers.EscapeLdapQuery(term);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("(&(objectClass=User)(objectCategory=Person)(|(sAMAccountName=*{0}*)(displayName=*{0}*)))", term), new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName",
|
||||
"sAMAccountName",
|
||||
"objectSid",
|
||||
"displayName",
|
||||
"sn",
|
||||
"givenName",
|
||||
"memberOf",
|
||||
"mail",
|
||||
"telephoneNumber"
|
||||
}, SearchScope.Subtree))
|
||||
{
|
||||
searcher.SizeLimit = 30;
|
||||
SearchResultCollection results = searcher.FindAll();
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
users.Add(ActiveDirectory.SearchResultToActiveDirectoryUserAccount(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
return users;
|
||||
}
|
||||
public static List<ActiveDirectoryOrganisationalUnit> GetOrganisationalUnitStructure()
|
||||
{
|
||||
ActiveDirectoryOrganisationalUnit DomainOUs = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Children = new System.Collections.Generic.List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
string defaultQualifiedDomainName = ActiveDirectoryHelpers.DefaultDomainQualifiedName;
|
||||
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("LDAP://{0}", defaultQualifiedDomainName)))
|
||||
{
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref DomainOUs, entry);
|
||||
}
|
||||
return DomainOUs.Children;
|
||||
}
|
||||
private static void GetOrganisationalUnitStructure_Recursive(ref ActiveDirectoryOrganisationalUnit ParentOU, DirectoryEntry Container)
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(Container, "(objectCategory=organizationalUnit)", new string[]
|
||||
{
|
||||
"name",
|
||||
"distinguishedName"
|
||||
}, SearchScope.OneLevel))
|
||||
{
|
||||
using (SearchResultCollection results = searcher.FindAll())
|
||||
{
|
||||
foreach (SearchResult result in results)
|
||||
{
|
||||
string i = result.Properties["name"][0].ToString();
|
||||
string dn = result.Properties["distinguishedName"][0].ToString();
|
||||
ActiveDirectoryOrganisationalUnit ChildOU = new ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
Name = i,
|
||||
Path = dn.Substring(0, dn.IndexOf(",DC=")),
|
||||
Children = new List<ActiveDirectoryOrganisationalUnit>()
|
||||
};
|
||||
ActiveDirectory.GetOrganisationalUnitStructure_Recursive(ref ChildOU, result.GetDirectoryEntry());
|
||||
if (ChildOU.Children.Count == 0)
|
||||
ChildOU.Children = null;
|
||||
ParentOU.Children.Add(ChildOU);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,186 +1,186 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryCachedGroups : ScheduledTask
|
||||
{
|
||||
private static ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>> _Cache = new ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>>();
|
||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
||||
|
||||
public static IEnumerable<string> GetGroups(IEnumerable<string> GroupCNs)
|
||||
{
|
||||
List<ADCachedGroup> groups = new List<ADCachedGroup>();
|
||||
|
||||
foreach (var groupCN in GroupCNs)
|
||||
foreach (var group in GetGroupsRecursive(groupCN, new Stack<ADCachedGroup>()))
|
||||
if (!groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
yield return group.FriendlyName;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> GetGroups(string GroupCN)
|
||||
{
|
||||
foreach (var group in GetGroupsRecursive(GroupCN, new Stack<ADCachedGroup>()))
|
||||
yield return group.FriendlyName;
|
||||
}
|
||||
private static IEnumerable<ADCachedGroup> GetGroupsRecursive(string GroupCN, Stack<ADCachedGroup> RecursiveTree)
|
||||
{
|
||||
var group = GetGroup(GroupCN);
|
||||
|
||||
if (group != null && !RecursiveTree.Contains(group))
|
||||
{
|
||||
yield return group;
|
||||
|
||||
if (group.MemberOf != null)
|
||||
{
|
||||
RecursiveTree.Push(group);
|
||||
|
||||
foreach (var memberOfGroupCN in group.MemberOf)
|
||||
foreach (var memberOfGroup in GetGroupsRecursive(memberOfGroupCN, RecursiveTree))
|
||||
yield return memberOfGroup;
|
||||
|
||||
RecursiveTree.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ADCachedGroup GetGroup(string GroupCN)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord = TryCache(GroupCN);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ADCachedGroup.LoadFromAD(GroupCN);
|
||||
SetValue(GroupCN, group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<ADCachedGroup, DateTime> TryCache(string GroupCN)
|
||||
{
|
||||
string groupCN = GroupCN.ToLower();
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
||||
if (_Cache.TryGetValue(groupCN, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
_Cache.TryRemove(groupCN, out groupRecord);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static bool SetValue(string GroupCN, ADCachedGroup GroupRecord)
|
||||
{
|
||||
string key = GroupCN.ToLower();
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord = new Tuple<ADCachedGroup, DateTime>(GroupRecord, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
||||
if (_Cache.ContainsKey(key))
|
||||
{
|
||||
Tuple<ADCachedGroup, DateTime> oldGroupRecord;
|
||||
if (_Cache.TryGetValue(key, out oldGroupRecord))
|
||||
{
|
||||
return _Cache.TryUpdate(key, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
return _Cache.TryAdd(key, groupRecord);
|
||||
}
|
||||
|
||||
private class ADCachedGroup
|
||||
{
|
||||
public string CN { get; private set; }
|
||||
public string FriendlyName { get; private set; }
|
||||
|
||||
public List<string> MemberOf { get; private set; }
|
||||
|
||||
public static ADCachedGroup LoadFromAD(string CN)
|
||||
{
|
||||
ADCachedGroup group = null;
|
||||
|
||||
using (DirectoryEntry groupDE = new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, CN)))
|
||||
{
|
||||
if (groupDE != null)
|
||||
{
|
||||
group = new ADCachedGroup()
|
||||
{
|
||||
CN = CN
|
||||
};
|
||||
|
||||
group.FriendlyName = (string)groupDE.Properties["sAMAccountName"].Value;
|
||||
|
||||
var groupMemberOf = groupDE.Properties["memberOf"];
|
||||
if (groupMemberOf != null && groupMemberOf.Count > 0)
|
||||
{
|
||||
group.MemberOf = groupMemberOf.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private ADCachedGroup()
|
||||
{
|
||||
// Private Constructor
|
||||
}
|
||||
}
|
||||
|
||||
private static void CleanStaleCache()
|
||||
{
|
||||
var groupKeys = _Cache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
||||
if (_Cache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
_Cache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext dbContext)
|
||||
{
|
||||
// Run @ every 15mins
|
||||
|
||||
// Next 15min interval
|
||||
DateTime now = DateTime.Now;
|
||||
int mins = (15 - (now.Minute % 15));
|
||||
if (mins < 10)
|
||||
mins += 15;
|
||||
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
|
||||
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
CleanStaleCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Services.Tasks;
|
||||
using Quartz;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryCachedGroups : ScheduledTask
|
||||
{
|
||||
private static ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>> _Cache = new ConcurrentDictionary<string, Tuple<ADCachedGroup, DateTime>>();
|
||||
private const long CacheTimeoutTicks = 6000000000; // 10 Minutes
|
||||
|
||||
public static IEnumerable<string> GetGroups(IEnumerable<string> GroupCNs)
|
||||
{
|
||||
List<ADCachedGroup> groups = new List<ADCachedGroup>();
|
||||
|
||||
foreach (var groupCN in GroupCNs)
|
||||
foreach (var group in GetGroupsRecursive(groupCN, new Stack<ADCachedGroup>()))
|
||||
if (!groups.Contains(group))
|
||||
{
|
||||
groups.Add(group);
|
||||
yield return group.FriendlyName;
|
||||
}
|
||||
}
|
||||
public static IEnumerable<string> GetGroups(string GroupCN)
|
||||
{
|
||||
foreach (var group in GetGroupsRecursive(GroupCN, new Stack<ADCachedGroup>()))
|
||||
yield return group.FriendlyName;
|
||||
}
|
||||
private static IEnumerable<ADCachedGroup> GetGroupsRecursive(string GroupCN, Stack<ADCachedGroup> RecursiveTree)
|
||||
{
|
||||
var group = GetGroup(GroupCN);
|
||||
|
||||
if (group != null && !RecursiveTree.Contains(group))
|
||||
{
|
||||
yield return group;
|
||||
|
||||
if (group.MemberOf != null)
|
||||
{
|
||||
RecursiveTree.Push(group);
|
||||
|
||||
foreach (var memberOfGroupCN in group.MemberOf)
|
||||
foreach (var memberOfGroup in GetGroupsRecursive(memberOfGroupCN, RecursiveTree))
|
||||
yield return memberOfGroup;
|
||||
|
||||
RecursiveTree.Pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static ADCachedGroup GetGroup(string GroupCN)
|
||||
{
|
||||
// Check Cache
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord = TryCache(GroupCN);
|
||||
|
||||
if (groupRecord == null)
|
||||
{
|
||||
// Load from AD
|
||||
var group = ADCachedGroup.LoadFromAD(GroupCN);
|
||||
SetValue(GroupCN, group);
|
||||
|
||||
return group;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return from Cache
|
||||
return groupRecord.Item1;
|
||||
}
|
||||
}
|
||||
|
||||
private static Tuple<ADCachedGroup, DateTime> TryCache(string GroupCN)
|
||||
{
|
||||
string groupCN = GroupCN.ToLower();
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
||||
if (_Cache.TryGetValue(groupCN, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 > DateTime.Now)
|
||||
return groupRecord;
|
||||
else
|
||||
_Cache.TryRemove(groupCN, out groupRecord);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
private static bool SetValue(string GroupCN, ADCachedGroup GroupRecord)
|
||||
{
|
||||
string key = GroupCN.ToLower();
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord = new Tuple<ADCachedGroup, DateTime>(GroupRecord, DateTime.Now.AddTicks(CacheTimeoutTicks));
|
||||
if (_Cache.ContainsKey(key))
|
||||
{
|
||||
Tuple<ADCachedGroup, DateTime> oldGroupRecord;
|
||||
if (_Cache.TryGetValue(key, out oldGroupRecord))
|
||||
{
|
||||
return _Cache.TryUpdate(key, groupRecord, oldGroupRecord);
|
||||
}
|
||||
}
|
||||
return _Cache.TryAdd(key, groupRecord);
|
||||
}
|
||||
|
||||
private class ADCachedGroup
|
||||
{
|
||||
public string CN { get; private set; }
|
||||
public string FriendlyName { get; private set; }
|
||||
|
||||
public List<string> MemberOf { get; private set; }
|
||||
|
||||
public static ADCachedGroup LoadFromAD(string CN)
|
||||
{
|
||||
ADCachedGroup group = null;
|
||||
|
||||
using (DirectoryEntry groupDE = new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, CN)))
|
||||
{
|
||||
if (groupDE != null)
|
||||
{
|
||||
group = new ADCachedGroup()
|
||||
{
|
||||
CN = CN
|
||||
};
|
||||
|
||||
group.FriendlyName = (string)groupDE.Properties["sAMAccountName"].Value;
|
||||
|
||||
var groupMemberOf = groupDE.Properties["memberOf"];
|
||||
if (groupMemberOf != null && groupMemberOf.Count > 0)
|
||||
{
|
||||
group.MemberOf = groupMemberOf.Cast<string>().ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
private ADCachedGroup()
|
||||
{
|
||||
// Private Constructor
|
||||
}
|
||||
}
|
||||
|
||||
private static void CleanStaleCache()
|
||||
{
|
||||
var groupKeys = _Cache.Keys.ToArray();
|
||||
foreach (string groupKey in groupKeys)
|
||||
{
|
||||
Tuple<ADCachedGroup, DateTime> groupRecord;
|
||||
if (_Cache.TryGetValue(groupKey, out groupRecord))
|
||||
{
|
||||
if (groupRecord.Item2 <= DateTime.Now)
|
||||
_Cache.TryRemove(groupKey, out groupRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string TaskName { get { return "AD Group Cache - Clean Stale Cache"; } }
|
||||
|
||||
public override bool SingleInstanceTask { get { return true; } }
|
||||
public override bool CancelInitiallySupported { get { return false; } }
|
||||
public override bool LogExceptionsOnly { get { return true; } }
|
||||
|
||||
public override void InitalizeScheduledTask(DiscoDataContext dbContext)
|
||||
{
|
||||
// Run @ every 15mins
|
||||
|
||||
// Next 15min interval
|
||||
DateTime now = DateTime.Now;
|
||||
int mins = (15 - (now.Minute % 15));
|
||||
if (mins < 10)
|
||||
mins += 15;
|
||||
DateTimeOffset startAt = new DateTimeOffset(now).AddMinutes(mins).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder.Create().StartAt(startAt).
|
||||
WithSchedule(SimpleScheduleBuilder.RepeatMinutelyForever(15));
|
||||
|
||||
this.ScheduleTask(triggerBuilder);
|
||||
}
|
||||
|
||||
protected override void ExecuteTask()
|
||||
{
|
||||
CleanStaleCache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +1,169 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryHelpers
|
||||
{
|
||||
#region Static Cached Properties
|
||||
private static string _DefaultDomainName;
|
||||
private static string _DefaultDomainPDCName;
|
||||
private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
|
||||
private static string _DefaultDomainNetBiosName;
|
||||
private static string _DefaultDomainQualifiedName;
|
||||
private static string _DefaultLdapPath;
|
||||
private static bool _DetermineDomainProperties_Loaded = false;
|
||||
private static object _DetermineDomainProperties_Lock = new object();
|
||||
internal static string DefaultDomainName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainPDCName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainPDCName;
|
||||
}
|
||||
}
|
||||
internal static System.Collections.Generic.List<string> DefaultDomainDCNames
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainDCNames;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainNetBiosName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainQualifiedName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultLdapPath
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultLdapPath;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDCLdapPath(string DC)
|
||||
{
|
||||
return string.Format("LDAP://{0}/", DC);
|
||||
}
|
||||
internal static DirectoryEntry DefaultLdapRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
}
|
||||
internal static DirectoryEntry DefaultDCLdapRoot(string DC)
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
|
||||
private static void DetermineDomainProperties()
|
||||
{
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
|
||||
{
|
||||
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
|
||||
foreach (DomainController dc in domain.DomainControllers)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
|
||||
ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
|
||||
{
|
||||
SearchResult result = searcher.FindOne();
|
||||
if (result != null)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool ConvertSidToStringSid(byte[] pSID, ref System.Text.StringBuilder ptrSid);
|
||||
internal static string ConvertBytesToSIDString(byte[] SID)
|
||||
{
|
||||
System.Text.StringBuilder sidString = new System.Text.StringBuilder();
|
||||
bool flag = ActiveDirectoryHelpers.ConvertSidToStringSid(SID, ref sidString);
|
||||
string ConvertBytesToSIDString;
|
||||
if (flag)
|
||||
{
|
||||
ConvertBytesToSIDString = sidString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertBytesToSIDString = null;
|
||||
}
|
||||
return ConvertBytesToSIDString;
|
||||
}
|
||||
|
||||
internal static string EscapeLdapQuery(string query)
|
||||
{
|
||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
||||
}
|
||||
internal static string FormatGuidForLdapQuery(System.Guid g)
|
||||
{
|
||||
checked
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
byte[] array = g.ToByteArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte b = array[i];
|
||||
sb.Append("\\");
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.DirectoryServices.ActiveDirectory;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryHelpers
|
||||
{
|
||||
#region Static Cached Properties
|
||||
private static string _DefaultDomainName;
|
||||
private static string _DefaultDomainPDCName;
|
||||
private static System.Collections.Generic.List<string> _DefaultDomainDCNames;
|
||||
private static string _DefaultDomainNetBiosName;
|
||||
private static string _DefaultDomainQualifiedName;
|
||||
private static string _DefaultLdapPath;
|
||||
private static bool _DetermineDomainProperties_Loaded = false;
|
||||
private static object _DetermineDomainProperties_Lock = new object();
|
||||
internal static string DefaultDomainName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainPDCName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainPDCName;
|
||||
}
|
||||
}
|
||||
internal static System.Collections.Generic.List<string> DefaultDomainDCNames
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainDCNames;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainNetBiosName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainNetBiosName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDomainQualifiedName
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
internal static string DefaultLdapPath
|
||||
{
|
||||
get
|
||||
{
|
||||
ActiveDirectoryHelpers.DetermineDomainProperties();
|
||||
return ActiveDirectoryHelpers._DefaultLdapPath;
|
||||
}
|
||||
}
|
||||
internal static string DefaultDCLdapPath(string DC)
|
||||
{
|
||||
return string.Format("LDAP://{0}/", DC);
|
||||
}
|
||||
internal static DirectoryEntry DefaultLdapRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
}
|
||||
internal static DirectoryEntry DefaultDCLdapRoot(string DC)
|
||||
{
|
||||
return new DirectoryEntry(string.Concat(ActiveDirectoryHelpers.DefaultDCLdapPath(DC), ActiveDirectoryHelpers.DefaultDomainQualifiedName));
|
||||
}
|
||||
|
||||
private static void DetermineDomainProperties()
|
||||
{
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
lock (ActiveDirectoryHelpers._DetermineDomainProperties_Lock)
|
||||
{
|
||||
|
||||
if (!ActiveDirectoryHelpers._DetermineDomainProperties_Loaded)
|
||||
{
|
||||
using (Domain domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain)))
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainName = domain.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainPDCName = domain.PdcRoleOwner.Name;
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames = new System.Collections.Generic.List<string>(domain.DomainControllers.Count);
|
||||
foreach (DomainController dc in domain.DomainControllers)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainDCNames.Add(dc.Name);
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DefaultDomainQualifiedName = string.Format("DC={0}", ActiveDirectoryHelpers._DefaultDomainName.Replace(".", ",DC="));
|
||||
ActiveDirectoryHelpers._DefaultLdapPath = string.Format("LDAP://{0}/", ActiveDirectoryHelpers._DefaultDomainPDCName);
|
||||
using (DirectoryEntry entry = new DirectoryEntry(string.Format("{0}CN=Partitions,CN=Configuration,{1}", ActiveDirectoryHelpers._DefaultLdapPath, ActiveDirectoryHelpers._DefaultDomainQualifiedName)))
|
||||
{
|
||||
using (DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectClass=crossRef)(nETBIOSName=*))", new string[] { "nETBIOSName" }))
|
||||
{
|
||||
SearchResult result = searcher.FindOne();
|
||||
if (result != null)
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = result.Properties["nETBIOSName"][0].ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ActiveDirectoryHelpers._DefaultDomainNetBiosName = ActiveDirectoryHelpers._DefaultDomainQualifiedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActiveDirectoryHelpers._DetermineDomainProperties_Loaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
[System.Runtime.InteropServices.DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool ConvertSidToStringSid(byte[] pSID, ref System.Text.StringBuilder ptrSid);
|
||||
internal static string ConvertBytesToSIDString(byte[] SID)
|
||||
{
|
||||
System.Text.StringBuilder sidString = new System.Text.StringBuilder();
|
||||
bool flag = ActiveDirectoryHelpers.ConvertSidToStringSid(SID, ref sidString);
|
||||
string ConvertBytesToSIDString;
|
||||
if (flag)
|
||||
{
|
||||
ConvertBytesToSIDString = sidString.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
ConvertBytesToSIDString = null;
|
||||
}
|
||||
return ConvertBytesToSIDString;
|
||||
}
|
||||
|
||||
internal static string EscapeLdapQuery(string query)
|
||||
{
|
||||
return query.Replace("*", "\\2a").Replace("(", "\\28").Replace(")", "\\29").Replace("\\", "\\5c").Replace("NUL", "\\00").Replace("/", "\\2f");
|
||||
}
|
||||
internal static string FormatGuidForLdapQuery(System.Guid g)
|
||||
{
|
||||
checked
|
||||
{
|
||||
System.Text.StringBuilder sb = new System.Text.StringBuilder();
|
||||
byte[] array = g.ToByteArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte b = array[i];
|
||||
sb.Append("\\");
|
||||
sb.Append(b.ToString("X2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,296 +1,296 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Text;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Management;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectoryMachineAccountExtensions
|
||||
{
|
||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
DeleteAccountRecursive(machineDE);
|
||||
|
||||
using (var machineDEParent = machineDE.Parent)
|
||||
{
|
||||
machineDEParent.Children.Remove(machineDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void DeleteAccountRecursive(DirectoryEntry parent)
|
||||
{
|
||||
List<DirectoryEntry> children = new List<DirectoryEntry>();
|
||||
foreach (DirectoryEntry child in parent.Children)
|
||||
children.Add(child);
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
DeleteAccountRecursive(child);
|
||||
parent.Children.Remove(child);
|
||||
child.Dispose();
|
||||
}
|
||||
}
|
||||
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, System.Guid updatedNetbootGUID)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection netbootGUIDProp = machineDE.Properties["netbootGUID"];
|
||||
bool flag = netbootGUIDProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
netbootGUIDProp.Clear();
|
||||
}
|
||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
|
||||
{
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection descriptionProp = machineDE.Properties["description"];
|
||||
bool flag = descriptionProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
descriptionProp.Clear();
|
||||
}
|
||||
flag = !string.IsNullOrEmpty(Description);
|
||||
if (flag)
|
||||
{
|
||||
descriptionProp.Add(Description);
|
||||
}
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
|
||||
{
|
||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
||||
bool flag = Device.AssignedUserId != null;
|
||||
if (flag)
|
||||
{
|
||||
descriptionBuilder.Append(Device.AssignedUser.Id);
|
||||
descriptionBuilder.Append(" (");
|
||||
descriptionBuilder.Append(Device.AssignedUser.DisplayName);
|
||||
descriptionBuilder.Append("); ");
|
||||
}
|
||||
flag = Device.DeviceModelId.HasValue;
|
||||
if (flag)
|
||||
{
|
||||
descriptionBuilder.Append(Device.DeviceModel.Description);
|
||||
descriptionBuilder.Append("; ");
|
||||
}
|
||||
descriptionBuilder.Append(Device.DeviceProfile.Description);
|
||||
descriptionBuilder.Append("; ");
|
||||
string description = descriptionBuilder.ToString().Trim();
|
||||
flag = (description.Length > 1024);
|
||||
if (flag)
|
||||
{
|
||||
description = description.Substring(0, 1024);
|
||||
}
|
||||
account.SetDescription(description);
|
||||
}
|
||||
|
||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
int updatedAccountControl = (accountControl | 2);
|
||||
if (accountControl != updatedAccountControl)
|
||||
{
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
if ((accountControl & 2) == 2)
|
||||
{
|
||||
int updatedAccountControl = (accountControl ^ 2);
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
System.Guid netbootGUID = System.Guid.Empty;
|
||||
bool flag = !string.IsNullOrWhiteSpace(UUID);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(UUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = !string.IsNullOrWhiteSpace(MACAddress);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(MACAddress);
|
||||
}
|
||||
}
|
||||
flag = (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID);
|
||||
bool UpdateNetbootGUID;
|
||||
if (flag)
|
||||
{
|
||||
account.SetNetbootGUID(netbootGUID);
|
||||
UpdateNetbootGUID = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNetbootGUID = false;
|
||||
}
|
||||
return UpdateNetbootGUID;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
||||
{
|
||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
||||
bool flag = strippedMACAddress.Length == 12;
|
||||
System.Guid NetbootGUIDFromMACAddress;
|
||||
if (flag)
|
||||
{
|
||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
||||
NetbootGUIDFromMACAddress = guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
||||
}
|
||||
return NetbootGUIDFromMACAddress;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromUUID(string UUID)
|
||||
{
|
||||
System.Guid result = new System.Guid(UUID);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.sAMAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.ObjectSid;
|
||||
case "netbootguid":
|
||||
return account.NetbootGUID;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
|
||||
{
|
||||
using (var p = new Ping())
|
||||
{
|
||||
PingReply reply = p.Send(account.DnsName, Timeout);
|
||||
return reply.Status;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't Work - WMI Limitation?
|
||||
// G# - 2012-06-18
|
||||
//public static void OnlineRenameComputer(this ActiveDirectoryMachineAccount account, string NewComputerName)
|
||||
//{
|
||||
// if (account.IsCriticalSystemObject)
|
||||
// throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
// try
|
||||
// {
|
||||
// IPStatus pingResult = account.PingComputer();
|
||||
// if (pingResult != IPStatus.Success)
|
||||
// throw new Exception(string.Format("Ping Error Result: {0}", pingResult.ToString()));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw new Exception(string.Format("Error trying to Ping the Device: {0}; {1}", account.DnsName, ex.Message), ex);
|
||||
// }
|
||||
|
||||
// ConnectionOptions wmiConnectionOptions = new ConnectionOptions()
|
||||
// {
|
||||
// Authentication = AuthenticationLevel.PacketPrivacy,
|
||||
// Impersonation = ImpersonationLevel.Impersonate,
|
||||
// EnablePrivileges = true,
|
||||
// Timeout = new TimeSpan(0, 0, 6)
|
||||
// };
|
||||
// ManagementPath wmiPath = new ManagementPath()
|
||||
// {
|
||||
// Server = account.DnsName,
|
||||
// NamespacePath = @"root\cimv2",
|
||||
// ClassName = "Win32_ComputerSystem"
|
||||
// };
|
||||
|
||||
// ManagementScope wmiScope = new ManagementScope(wmiPath, wmiConnectionOptions);
|
||||
|
||||
// ObjectGetOptions wmiGetOptions = new ObjectGetOptions() { Timeout = new TimeSpan(0, 1, 0) };
|
||||
|
||||
// using (ManagementClass wmiClass = new ManagementClass(wmiScope, wmiPath, wmiGetOptions))
|
||||
// {
|
||||
// foreach (ManagementObject wmiWin32ComputerSystem in wmiClass.GetInstances())
|
||||
// {
|
||||
// UInt32 result = (UInt32)wmiWin32ComputerSystem.InvokeMethod("Rename", new object[] { NewComputerName });
|
||||
// if (result != 0)
|
||||
// throw new Exception(string.Format("Error Renaming Computer; WMI Remote Method 'Rename' returned: {0}", result));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
public static void MoveOrganisationUnit(this ActiveDirectoryMachineAccount account, string NewOrganisationUnit)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
if (!account.ParentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
string ouPath;
|
||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
||||
ouPath = string.Format("{0}CN=Computers,{1}", ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
else
|
||||
ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, NewOrganisationUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
using (DirectoryEntry i = new DirectoryEntry(account.Path) { UsePropertyCache = false })
|
||||
{
|
||||
i.MoveTo(ou);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using Disco.Models.Repository;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
using System.Text;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Management;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public static class ActiveDirectoryMachineAccountExtensions
|
||||
{
|
||||
public static void DeleteAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
DeleteAccountRecursive(machineDE);
|
||||
|
||||
using (var machineDEParent = machineDE.Parent)
|
||||
{
|
||||
machineDEParent.Children.Remove(machineDE);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void DeleteAccountRecursive(DirectoryEntry parent)
|
||||
{
|
||||
List<DirectoryEntry> children = new List<DirectoryEntry>();
|
||||
foreach (DirectoryEntry child in parent.Children)
|
||||
children.Add(child);
|
||||
|
||||
foreach (var child in children)
|
||||
{
|
||||
DeleteAccountRecursive(child);
|
||||
parent.Children.Remove(child);
|
||||
child.Dispose();
|
||||
}
|
||||
}
|
||||
private static void SetNetbootGUID(this ActiveDirectoryMachineAccount account, System.Guid updatedNetbootGUID)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection netbootGUIDProp = machineDE.Properties["netbootGUID"];
|
||||
bool flag = netbootGUIDProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
netbootGUIDProp.Clear();
|
||||
}
|
||||
netbootGUIDProp.Add(updatedNetbootGUID.ToByteArray());
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, string Description)
|
||||
{
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
PropertyValueCollection descriptionProp = machineDE.Properties["description"];
|
||||
bool flag = descriptionProp.Count > 0;
|
||||
if (flag)
|
||||
{
|
||||
descriptionProp.Clear();
|
||||
}
|
||||
flag = !string.IsNullOrEmpty(Description);
|
||||
if (flag)
|
||||
{
|
||||
descriptionProp.Add(Description);
|
||||
}
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
public static void SetDescription(this ActiveDirectoryMachineAccount account, Device Device)
|
||||
{
|
||||
System.Text.StringBuilder descriptionBuilder = new System.Text.StringBuilder();
|
||||
bool flag = Device.AssignedUserId != null;
|
||||
if (flag)
|
||||
{
|
||||
descriptionBuilder.Append(Device.AssignedUser.Id);
|
||||
descriptionBuilder.Append(" (");
|
||||
descriptionBuilder.Append(Device.AssignedUser.DisplayName);
|
||||
descriptionBuilder.Append("); ");
|
||||
}
|
||||
flag = Device.DeviceModelId.HasValue;
|
||||
if (flag)
|
||||
{
|
||||
descriptionBuilder.Append(Device.DeviceModel.Description);
|
||||
descriptionBuilder.Append("; ");
|
||||
}
|
||||
descriptionBuilder.Append(Device.DeviceProfile.Description);
|
||||
descriptionBuilder.Append("; ");
|
||||
string description = descriptionBuilder.ToString().Trim();
|
||||
flag = (description.Length > 1024);
|
||||
if (flag)
|
||||
{
|
||||
description = description.Substring(0, 1024);
|
||||
}
|
||||
account.SetDescription(description);
|
||||
}
|
||||
|
||||
public static void DisableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
int updatedAccountControl = (accountControl | 2);
|
||||
if (accountControl != updatedAccountControl)
|
||||
{
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void EnableAccount(this ActiveDirectoryMachineAccount account)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
using (DirectoryEntry machineDE = new DirectoryEntry(account.Path))
|
||||
{
|
||||
int accountControl = (int)machineDE.Properties["userAccountControl"][0];
|
||||
if ((accountControl & 2) == 2)
|
||||
{
|
||||
int updatedAccountControl = (accountControl ^ 2);
|
||||
machineDE.Properties["userAccountControl"][0] = updatedAccountControl;
|
||||
machineDE.CommitChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool UpdateNetbootGUID(this ActiveDirectoryMachineAccount account, string UUID, string MACAddress)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
System.Guid netbootGUID = System.Guid.Empty;
|
||||
bool flag = !string.IsNullOrWhiteSpace(UUID);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromUUID(UUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = !string.IsNullOrWhiteSpace(MACAddress);
|
||||
if (flag)
|
||||
{
|
||||
netbootGUID = ActiveDirectoryMachineAccountExtensions.NetbootGUIDFromMACAddress(MACAddress);
|
||||
}
|
||||
}
|
||||
flag = (netbootGUID != System.Guid.Empty && netbootGUID != account.NetbootGUID);
|
||||
bool UpdateNetbootGUID;
|
||||
if (flag)
|
||||
{
|
||||
account.SetNetbootGUID(netbootGUID);
|
||||
UpdateNetbootGUID = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateNetbootGUID = false;
|
||||
}
|
||||
return UpdateNetbootGUID;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromMACAddress(string MACAddress)
|
||||
{
|
||||
string strippedMACAddress = MACAddress.Trim().Replace(":", string.Empty).Replace("-", string.Empty);
|
||||
bool flag = strippedMACAddress.Length == 12;
|
||||
System.Guid NetbootGUIDFromMACAddress;
|
||||
if (flag)
|
||||
{
|
||||
System.Guid guid = new System.Guid(string.Format("00000000-0000-0000-0000-{0}", strippedMACAddress));
|
||||
NetbootGUIDFromMACAddress = guid;
|
||||
}
|
||||
else
|
||||
{
|
||||
NetbootGUIDFromMACAddress = System.Guid.Empty;
|
||||
}
|
||||
return NetbootGUIDFromMACAddress;
|
||||
}
|
||||
internal static System.Guid NetbootGUIDFromUUID(string UUID)
|
||||
{
|
||||
System.Guid result = new System.Guid(UUID);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryMachineAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.sAMAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.ObjectSid;
|
||||
case "netbootguid":
|
||||
return account.NetbootGUID;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IPStatus PingComputer(this ActiveDirectoryMachineAccount account, int Timeout = 2000)
|
||||
{
|
||||
using (var p = new Ping())
|
||||
{
|
||||
PingReply reply = p.Send(account.DnsName, Timeout);
|
||||
return reply.Status;
|
||||
}
|
||||
}
|
||||
|
||||
// Didn't Work - WMI Limitation?
|
||||
// G# - 2012-06-18
|
||||
//public static void OnlineRenameComputer(this ActiveDirectoryMachineAccount account, string NewComputerName)
|
||||
//{
|
||||
// if (account.IsCriticalSystemObject)
|
||||
// throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
// try
|
||||
// {
|
||||
// IPStatus pingResult = account.PingComputer();
|
||||
// if (pingResult != IPStatus.Success)
|
||||
// throw new Exception(string.Format("Ping Error Result: {0}", pingResult.ToString()));
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// throw new Exception(string.Format("Error trying to Ping the Device: {0}; {1}", account.DnsName, ex.Message), ex);
|
||||
// }
|
||||
|
||||
// ConnectionOptions wmiConnectionOptions = new ConnectionOptions()
|
||||
// {
|
||||
// Authentication = AuthenticationLevel.PacketPrivacy,
|
||||
// Impersonation = ImpersonationLevel.Impersonate,
|
||||
// EnablePrivileges = true,
|
||||
// Timeout = new TimeSpan(0, 0, 6)
|
||||
// };
|
||||
// ManagementPath wmiPath = new ManagementPath()
|
||||
// {
|
||||
// Server = account.DnsName,
|
||||
// NamespacePath = @"root\cimv2",
|
||||
// ClassName = "Win32_ComputerSystem"
|
||||
// };
|
||||
|
||||
// ManagementScope wmiScope = new ManagementScope(wmiPath, wmiConnectionOptions);
|
||||
|
||||
// ObjectGetOptions wmiGetOptions = new ObjectGetOptions() { Timeout = new TimeSpan(0, 1, 0) };
|
||||
|
||||
// using (ManagementClass wmiClass = new ManagementClass(wmiScope, wmiPath, wmiGetOptions))
|
||||
// {
|
||||
// foreach (ManagementObject wmiWin32ComputerSystem in wmiClass.GetInstances())
|
||||
// {
|
||||
// UInt32 result = (UInt32)wmiWin32ComputerSystem.InvokeMethod("Rename", new object[] { NewComputerName });
|
||||
// if (result != 0)
|
||||
// throw new Exception(string.Format("Error Renaming Computer; WMI Remote Method 'Rename' returned: {0}", result));
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
public static void MoveOrganisationUnit(this ActiveDirectoryMachineAccount account, string NewOrganisationUnit)
|
||||
{
|
||||
if (account.IsCriticalSystemObject)
|
||||
throw new InvalidOperationException(string.Format("This account {0} is a Critical System Active Directory Object and Disco refuses to modify it", account.DistinguishedName));
|
||||
|
||||
if (!account.ParentDistinguishedName.Equals(NewOrganisationUnit, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
string ouPath;
|
||||
if (string.IsNullOrWhiteSpace(NewOrganisationUnit))
|
||||
ouPath = string.Format("{0}CN=Computers,{1}", ActiveDirectoryHelpers.DefaultLdapPath, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
else
|
||||
ouPath = string.Format("{0}{1},{2}", ActiveDirectoryHelpers.DefaultLdapPath, NewOrganisationUnit, ActiveDirectoryHelpers.DefaultDomainQualifiedName);
|
||||
|
||||
using (DirectoryEntry ou = new DirectoryEntry(ouPath))
|
||||
{
|
||||
using (DirectoryEntry i = new DirectoryEntry(account.Path) { UsePropertyCache = false })
|
||||
{
|
||||
i.MoveTo(ou);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
public class ActiveDirectoryOrganisationalUnit
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public List<ActiveDirectoryOrganisationalUnit> Children { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using Disco.Models.Repository;
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryUserAccountExtensions
|
||||
{
|
||||
public static bool HasRole(this ActiveDirectoryUserAccount account, string Role)
|
||||
{
|
||||
return account.Groups != null && account.Groups.Contains(Role.ToLower());
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.sAMAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.ObjectSid;
|
||||
case "sn":
|
||||
return account.Surname;
|
||||
case "givenname":
|
||||
return account.GivenName;
|
||||
case "mail":
|
||||
return account.Email;
|
||||
case "telephonenumber":
|
||||
return account.Phone;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using Disco.Models.Interop.ActiveDirectory;
|
||||
using System;
|
||||
using Disco.Models.Repository;
|
||||
namespace Disco.BI.Interop.ActiveDirectory
|
||||
{
|
||||
internal static class ActiveDirectoryUserAccountExtensions
|
||||
{
|
||||
public static bool HasRole(this ActiveDirectoryUserAccount account, string Role)
|
||||
{
|
||||
return account.Groups != null && account.Groups.Contains(Role.ToLower());
|
||||
}
|
||||
|
||||
public static object GetPropertyValue(this ActiveDirectoryUserAccount account, string PropertyName, int Index = 0)
|
||||
{
|
||||
switch (PropertyName.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return account.Name;
|
||||
case "samaccountname":
|
||||
return account.sAMAccountName;
|
||||
case "distinguishedname":
|
||||
return account.DistinguishedName;
|
||||
case "objectsid":
|
||||
return account.ObjectSid;
|
||||
case "sn":
|
||||
return account.Surname;
|
||||
case "givenname":
|
||||
return account.GivenName;
|
||||
case "mail":
|
||||
return account.Email;
|
||||
case "telephonenumber":
|
||||
return account.Phone;
|
||||
default:
|
||||
object[] adProperty;
|
||||
if (account.LoadedProperties.TryGetValue(PropertyName, out adProperty) && Index <= adProperty.Length)
|
||||
return adProperty[Index];
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,85 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Disco.BI.Interop
|
||||
{
|
||||
public static class MimeTypes
|
||||
{
|
||||
public static string ResolveMimeType(string Filename)
|
||||
{
|
||||
string fileExtension;
|
||||
if (Filename.Contains("."))
|
||||
fileExtension = Filename.Substring(Filename.LastIndexOf(".") + 1).ToLower();
|
||||
else
|
||||
fileExtension = Filename.ToLower();
|
||||
|
||||
// Try Known Mime Types
|
||||
switch (fileExtension)
|
||||
{
|
||||
case "pdf":
|
||||
return "application/pdf";
|
||||
case "doc":
|
||||
return "application/msword";
|
||||
case "docx":
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
case "docm":
|
||||
return "application/vnd.ms-word.document.macroEnabled.12";
|
||||
case "xml":
|
||||
return "text/xml";
|
||||
case "xls":
|
||||
return "application/vnd.ms-excel";
|
||||
case "xlsx":
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
case "xlsm":
|
||||
return "application/vnd.ms-excel.sheet.macroEnabled.12";
|
||||
case "csv":
|
||||
return "application/vnd.ms-excel";
|
||||
case "jpg":
|
||||
return "image/jpeg";
|
||||
case "gif":
|
||||
return "image/gif";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "bmp":
|
||||
return "image/bmp";
|
||||
case "avi":
|
||||
return "video/avi";
|
||||
case "mpeg":
|
||||
case "mpg":
|
||||
return "video/mpeg";
|
||||
case "mp3":
|
||||
return "audio/mpeg";
|
||||
case "mp4":
|
||||
return "video/mp4";
|
||||
case "wmv":
|
||||
return "video/x-ms-wmv";
|
||||
case "mov":
|
||||
return "video/quicktime";
|
||||
}
|
||||
|
||||
// Check System Registry
|
||||
try
|
||||
{
|
||||
RegistryKey regExtensionKey = Registry.ClassesRoot.OpenSubKey("." + fileExtension);
|
||||
if (regExtensionKey != null)
|
||||
{
|
||||
string regExtensionContentType = regExtensionKey.GetValue("Content Type") as string;
|
||||
if (regExtensionContentType != null)
|
||||
{
|
||||
return regExtensionContentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore Errors
|
||||
}
|
||||
|
||||
// Return Default
|
||||
return "unknown/unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace Disco.BI.Interop
|
||||
{
|
||||
public static class MimeTypes
|
||||
{
|
||||
public static string ResolveMimeType(string Filename)
|
||||
{
|
||||
string fileExtension;
|
||||
if (Filename.Contains("."))
|
||||
fileExtension = Filename.Substring(Filename.LastIndexOf(".") + 1).ToLower();
|
||||
else
|
||||
fileExtension = Filename.ToLower();
|
||||
|
||||
// Try Known Mime Types
|
||||
switch (fileExtension)
|
||||
{
|
||||
case "pdf":
|
||||
return "application/pdf";
|
||||
case "doc":
|
||||
return "application/msword";
|
||||
case "docx":
|
||||
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
|
||||
case "docm":
|
||||
return "application/vnd.ms-word.document.macroEnabled.12";
|
||||
case "xml":
|
||||
return "text/xml";
|
||||
case "xls":
|
||||
return "application/vnd.ms-excel";
|
||||
case "xlsx":
|
||||
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
case "xlsm":
|
||||
return "application/vnd.ms-excel.sheet.macroEnabled.12";
|
||||
case "csv":
|
||||
return "application/vnd.ms-excel";
|
||||
case "jpg":
|
||||
return "image/jpeg";
|
||||
case "gif":
|
||||
return "image/gif";
|
||||
case "png":
|
||||
return "image/png";
|
||||
case "bmp":
|
||||
return "image/bmp";
|
||||
case "avi":
|
||||
return "video/avi";
|
||||
case "mpeg":
|
||||
case "mpg":
|
||||
return "video/mpeg";
|
||||
case "mp3":
|
||||
return "audio/mpeg";
|
||||
case "mp4":
|
||||
return "video/mp4";
|
||||
case "wmv":
|
||||
return "video/x-ms-wmv";
|
||||
case "mov":
|
||||
return "video/quicktime";
|
||||
}
|
||||
|
||||
// Check System Registry
|
||||
try
|
||||
{
|
||||
RegistryKey regExtensionKey = Registry.ClassesRoot.OpenSubKey("." + fileExtension);
|
||||
if (regExtensionKey != null)
|
||||
{
|
||||
string regExtensionContentType = regExtensionKey.GetValue("Content Type") as string;
|
||||
if (regExtensionContentType != null)
|
||||
{
|
||||
return regExtensionContentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore Errors
|
||||
}
|
||||
|
||||
// Return Default
|
||||
return "unknown/unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,251 +1,251 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using System.IO;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.Collections.Concurrent;
|
||||
using Disco.BI.Expressions;
|
||||
using System.Collections;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.BI.Expressions;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
public static class PdfGenerator
|
||||
{
|
||||
|
||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
||||
{
|
||||
if (DataObjects.Length > 0)
|
||||
{
|
||||
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
|
||||
using (Models.BI.DocumentTemplates.DocumentState state = Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
||||
{
|
||||
foreach (object d in DataObjects)
|
||||
{
|
||||
generatedPdfs.Add(dt.GeneratePdf(dbContext, d, CreatorUser, Timestamp, state, true));
|
||||
state.SequenceNumber++;
|
||||
state.FlushScopeCache();
|
||||
}
|
||||
}
|
||||
if (generatedPdfs.Count == 1)
|
||||
{
|
||||
return generatedPdfs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream bulkPdf = DocumentTemplateBI.Utilities.JoinPdfs(generatedPdfs.ToArray());
|
||||
foreach (Stream singlePdf in generatedPdfs)
|
||||
singlePdf.Dispose();
|
||||
return bulkPdf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
||||
{
|
||||
object[] DataObjects;
|
||||
|
||||
switch (dt.Scope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
DataObjects = dbContext.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToArray();
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
int[] intDataObjectsIds = DataObjectsIds.Select(i => int.Parse(i)).ToArray();
|
||||
DataObjects = dbContext.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray();
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
DataObjects = new object[DataObjectsIds.Length];
|
||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
||||
{
|
||||
DataObjects[idIndex] = UserBI.UserCache.GetUser(DataObjectsIds[idIndex], dbContext, true);
|
||||
if (DataObjects[idIndex] == null)
|
||||
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid DocumentType Scope");
|
||||
}
|
||||
|
||||
return GenerateBulkFromTemplate(dt, dbContext, CreatorUser, Timestamp, DataObjects);
|
||||
}
|
||||
|
||||
public static System.IO.Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
||||
{
|
||||
// Validate Data
|
||||
switch (dt.Scope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
if (!(Data is Device))
|
||||
throw new ArgumentException("This AttachmentType is configured for Devices only", "Data");
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
if (!(Data is Job))
|
||||
throw new ArgumentException("This AttachmentType is configured for Jobs only", "Data");
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
if (!(Data is User))
|
||||
throw new ArgumentException("This AttachmentType is configured for Users only", "Data");
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid AttachmentType Scope");
|
||||
}
|
||||
|
||||
dbContext.Configuration.LazyLoadingEnabled = true;
|
||||
|
||||
// Override FlattenFields if Document Template instructs.
|
||||
if (dt.FlattenForm)
|
||||
FlattenFields = true;
|
||||
|
||||
ConcurrentDictionary<string, Expression> expressionCache = dt.PdfExpressionsFromCache(dbContext);
|
||||
|
||||
string templateFilename = dt.RepositoryFilename(dbContext);
|
||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
||||
|
||||
MemoryStream pdfGeneratedStream = new MemoryStream();
|
||||
PdfStamper pdfStamper = new PdfStamper(pdfReader, pdfGeneratedStream);
|
||||
|
||||
pdfStamper.FormFlattening = FlattenFields;
|
||||
pdfStamper.Writer.CloseStream = false;
|
||||
|
||||
IDictionary expressionVariables = Expression.StandardVariables(dt, dbContext, CreatorUser, TimeStamp, State);
|
||||
|
||||
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
||||
{
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.Id, TimeStamp);
|
||||
if (FlattenFields)
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
||||
else
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldValue);
|
||||
|
||||
IList<AcroFields.FieldPosition> pdfFieldPositions = pdfStamper.AcroFields.GetFieldPositions(pdfFieldKey);
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.Id, TimeStamp, pdfFieldPosition.page);
|
||||
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
||||
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
||||
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfBarcodeImage);
|
||||
}
|
||||
// Hide Fields
|
||||
PdfDictionary field = fields.GetValue(0);
|
||||
if ((PdfName)field.Get(PdfName.TYPE) == PdfName.ANNOT)
|
||||
{
|
||||
field.Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
else
|
||||
{
|
||||
PdfArray fieldKids = (PdfArray)field.Get(PdfName.KIDS);
|
||||
foreach (PdfIndirectReference fieldKidRef in fieldKids)
|
||||
{
|
||||
((PdfDictionary)pdfReader.GetPdfObject(fieldKidRef.Number)).Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression fieldExpression = null;
|
||||
if (expressionCache.TryGetValue(pdfFieldKey, out fieldExpression))
|
||||
{
|
||||
if (fieldExpression.IsDynamic)
|
||||
{
|
||||
Tuple<string, bool, object> fieldExpressionResult = fieldExpression.Evaluate(Data, expressionVariables);
|
||||
|
||||
if (fieldExpressionResult.Item3 != null)
|
||||
{
|
||||
IImageExpressionResult imageResult = (fieldExpressionResult.Item3 as IImageExpressionResult);
|
||||
if (imageResult != null)
|
||||
{
|
||||
// Output Image
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
IList<AcroFields.FieldPosition> pdfFieldPositions = pdfStamper.AcroFields.GetFieldPositions(pdfFieldKey);
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(imageResult.GetImage((int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height));
|
||||
pdfImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfImage);
|
||||
}
|
||||
if (!fieldExpressionResult.Item2 && !imageResult.ShowField)
|
||||
{
|
||||
// Hide Fields
|
||||
PdfDictionary field = fields.GetValue(0);
|
||||
if ((PdfName)field.Get(PdfName.TYPE) == PdfName.ANNOT)
|
||||
{
|
||||
field.Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
else
|
||||
{
|
||||
PdfArray fieldKids = (PdfArray)field.Get(PdfName.KIDS);
|
||||
foreach (PdfIndirectReference fieldKidRef in fieldKids)
|
||||
{
|
||||
((PdfDictionary)pdfReader.GetPdfObject(fieldKidRef.Number)).Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldExpressionResult.Item1);
|
||||
|
||||
if (fieldExpressionResult.Item2) // Expression Error
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
PdfDictionary field = fields.GetValue(pdfFieldOrdinal);
|
||||
PdfDictionary fieldMK;
|
||||
if (field.Contains(PdfName.MK))
|
||||
fieldMK = field.GetAsDict(PdfName.MK);
|
||||
else
|
||||
{
|
||||
fieldMK = new PdfDictionary(PdfName.MK);
|
||||
field.Put(PdfName.MK, fieldMK);
|
||||
}
|
||||
fieldMK.Put(PdfName.BC, new PdfArray(new float[] { 1, 0, 0 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Pdf template field expressions are out of sync with the expression cache");
|
||||
}
|
||||
}
|
||||
State.FlushFieldCache();
|
||||
}
|
||||
|
||||
pdfStamper.Close();
|
||||
pdfReader.Close();
|
||||
|
||||
if (dt.Scope == DocumentTemplate.DocumentTemplateScopes.Job)
|
||||
{
|
||||
// Write Job Log
|
||||
|
||||
Job j = (Job)Data;
|
||||
JobLog jl = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = CreatorUser.Id,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
|
||||
dbContext.JobLogs.Add(jl);
|
||||
}
|
||||
|
||||
pdfGeneratedStream.Position = 0;
|
||||
return pdfGeneratedStream;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.DocumentTemplates;
|
||||
using System.IO;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.Collections.Concurrent;
|
||||
using Disco.BI.Expressions;
|
||||
using System.Collections;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.BI.Expressions;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
public static class PdfGenerator
|
||||
{
|
||||
|
||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params object[] DataObjects)
|
||||
{
|
||||
if (DataObjects.Length > 0)
|
||||
{
|
||||
List<Stream> generatedPdfs = new List<Stream>(DataObjects.Length);
|
||||
using (Models.BI.DocumentTemplates.DocumentState state = Models.BI.DocumentTemplates.DocumentState.DefaultState())
|
||||
{
|
||||
foreach (object d in DataObjects)
|
||||
{
|
||||
generatedPdfs.Add(dt.GeneratePdf(dbContext, d, CreatorUser, Timestamp, state, true));
|
||||
state.SequenceNumber++;
|
||||
state.FlushScopeCache();
|
||||
}
|
||||
}
|
||||
if (generatedPdfs.Count == 1)
|
||||
{
|
||||
return generatedPdfs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream bulkPdf = DocumentTemplateBI.Utilities.JoinPdfs(generatedPdfs.ToArray());
|
||||
foreach (Stream singlePdf in generatedPdfs)
|
||||
singlePdf.Dispose();
|
||||
return bulkPdf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static System.IO.Stream GenerateBulkFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, User CreatorUser, System.DateTime Timestamp, params string[] DataObjectsIds)
|
||||
{
|
||||
object[] DataObjects;
|
||||
|
||||
switch (dt.Scope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
DataObjects = dbContext.Devices.Where(d => DataObjectsIds.Contains(d.SerialNumber)).ToArray();
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
int[] intDataObjectsIds = DataObjectsIds.Select(i => int.Parse(i)).ToArray();
|
||||
DataObjects = dbContext.Jobs.Where(j => intDataObjectsIds.Contains(j.Id)).ToArray();
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
DataObjects = new object[DataObjectsIds.Length];
|
||||
for (int idIndex = 0; idIndex < DataObjectsIds.Length; idIndex++)
|
||||
{
|
||||
DataObjects[idIndex] = UserBI.UserCache.GetUser(DataObjectsIds[idIndex], dbContext, true);
|
||||
if (DataObjects[idIndex] == null)
|
||||
throw new Exception(string.Format("Unknown Username specified: {0}", DataObjectsIds[idIndex]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid DocumentType Scope");
|
||||
}
|
||||
|
||||
return GenerateBulkFromTemplate(dt, dbContext, CreatorUser, Timestamp, DataObjects);
|
||||
}
|
||||
|
||||
public static System.IO.Stream GenerateFromTemplate(DocumentTemplate dt, DiscoDataContext dbContext, object Data, User CreatorUser, System.DateTime TimeStamp, DocumentState State, bool FlattenFields = false)
|
||||
{
|
||||
// Validate Data
|
||||
switch (dt.Scope)
|
||||
{
|
||||
case DocumentTemplate.DocumentTemplateScopes.Device:
|
||||
if (!(Data is Device))
|
||||
throw new ArgumentException("This AttachmentType is configured for Devices only", "Data");
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.Job:
|
||||
if (!(Data is Job))
|
||||
throw new ArgumentException("This AttachmentType is configured for Jobs only", "Data");
|
||||
break;
|
||||
case DocumentTemplate.DocumentTemplateScopes.User:
|
||||
if (!(Data is User))
|
||||
throw new ArgumentException("This AttachmentType is configured for Users only", "Data");
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid AttachmentType Scope");
|
||||
}
|
||||
|
||||
dbContext.Configuration.LazyLoadingEnabled = true;
|
||||
|
||||
// Override FlattenFields if Document Template instructs.
|
||||
if (dt.FlattenForm)
|
||||
FlattenFields = true;
|
||||
|
||||
ConcurrentDictionary<string, Expression> expressionCache = dt.PdfExpressionsFromCache(dbContext);
|
||||
|
||||
string templateFilename = dt.RepositoryFilename(dbContext);
|
||||
PdfReader pdfReader = new PdfReader(templateFilename);
|
||||
|
||||
MemoryStream pdfGeneratedStream = new MemoryStream();
|
||||
PdfStamper pdfStamper = new PdfStamper(pdfReader, pdfGeneratedStream);
|
||||
|
||||
pdfStamper.FormFlattening = FlattenFields;
|
||||
pdfStamper.Writer.CloseStream = false;
|
||||
|
||||
IDictionary expressionVariables = Expression.StandardVariables(dt, dbContext, CreatorUser, TimeStamp, State);
|
||||
|
||||
foreach (string pdfFieldKey in pdfStamper.AcroFields.Fields.Keys)
|
||||
{
|
||||
if (pdfFieldKey.Equals("DiscoAttachmentId", StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
string fieldValue = dt.UniqueIdentifier(Data, CreatorUser.Id, TimeStamp);
|
||||
if (FlattenFields)
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, String.Empty);
|
||||
else
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldValue);
|
||||
|
||||
IList<AcroFields.FieldPosition> pdfFieldPositions = pdfStamper.AcroFields.GetFieldPositions(pdfFieldKey);
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||
string pdfBarcodeContent = dt.UniquePageIdentifier(Data, CreatorUser.Id, TimeStamp, pdfFieldPosition.page);
|
||||
BarcodeQRCode pdfBarcode = new BarcodeQRCode(pdfBarcodeContent, (int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height, null);
|
||||
iTextSharp.text.Image pdfBarcodeImage = pdfBarcode.GetImage();
|
||||
pdfBarcodeImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfBarcodeImage);
|
||||
}
|
||||
// Hide Fields
|
||||
PdfDictionary field = fields.GetValue(0);
|
||||
if ((PdfName)field.Get(PdfName.TYPE) == PdfName.ANNOT)
|
||||
{
|
||||
field.Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
else
|
||||
{
|
||||
PdfArray fieldKids = (PdfArray)field.Get(PdfName.KIDS);
|
||||
foreach (PdfIndirectReference fieldKidRef in fieldKids)
|
||||
{
|
||||
((PdfDictionary)pdfReader.GetPdfObject(fieldKidRef.Number)).Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Expression fieldExpression = null;
|
||||
if (expressionCache.TryGetValue(pdfFieldKey, out fieldExpression))
|
||||
{
|
||||
if (fieldExpression.IsDynamic)
|
||||
{
|
||||
Tuple<string, bool, object> fieldExpressionResult = fieldExpression.Evaluate(Data, expressionVariables);
|
||||
|
||||
if (fieldExpressionResult.Item3 != null)
|
||||
{
|
||||
IImageExpressionResult imageResult = (fieldExpressionResult.Item3 as IImageExpressionResult);
|
||||
if (imageResult != null)
|
||||
{
|
||||
// Output Image
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
IList<AcroFields.FieldPosition> pdfFieldPositions = pdfStamper.AcroFields.GetFieldPositions(pdfFieldKey);
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
AcroFields.FieldPosition pdfFieldPosition = pdfFieldPositions[pdfFieldOrdinal];
|
||||
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(imageResult.GetImage((int)pdfFieldPosition.position.Width, (int)pdfFieldPosition.position.Height));
|
||||
pdfImage.SetAbsolutePosition(pdfFieldPosition.position.Left, pdfFieldPosition.position.Bottom);
|
||||
pdfStamper.GetOverContent(pdfFieldPosition.page).AddImage(pdfImage);
|
||||
}
|
||||
if (!fieldExpressionResult.Item2 && !imageResult.ShowField)
|
||||
{
|
||||
// Hide Fields
|
||||
PdfDictionary field = fields.GetValue(0);
|
||||
if ((PdfName)field.Get(PdfName.TYPE) == PdfName.ANNOT)
|
||||
{
|
||||
field.Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
else
|
||||
{
|
||||
PdfArray fieldKids = (PdfArray)field.Get(PdfName.KIDS);
|
||||
foreach (PdfIndirectReference fieldKidRef in fieldKids)
|
||||
{
|
||||
((PdfDictionary)pdfReader.GetPdfObject(fieldKidRef.Number)).Put(PdfName.F, new PdfNumber(6));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pdfStamper.AcroFields.SetField(pdfFieldKey, fieldExpressionResult.Item1);
|
||||
|
||||
if (fieldExpressionResult.Item2) // Expression Error
|
||||
{
|
||||
AcroFields.Item fields = pdfStamper.AcroFields.Fields[pdfFieldKey];
|
||||
for (int pdfFieldOrdinal = 0; pdfFieldOrdinal < fields.Size; pdfFieldOrdinal++)
|
||||
{
|
||||
PdfDictionary field = fields.GetValue(pdfFieldOrdinal);
|
||||
PdfDictionary fieldMK;
|
||||
if (field.Contains(PdfName.MK))
|
||||
fieldMK = field.GetAsDict(PdfName.MK);
|
||||
else
|
||||
{
|
||||
fieldMK = new PdfDictionary(PdfName.MK);
|
||||
field.Put(PdfName.MK, fieldMK);
|
||||
}
|
||||
fieldMK.Put(PdfName.BC, new PdfArray(new float[] { 1, 0, 0 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Pdf template field expressions are out of sync with the expression cache");
|
||||
}
|
||||
}
|
||||
State.FlushFieldCache();
|
||||
}
|
||||
|
||||
pdfStamper.Close();
|
||||
pdfReader.Close();
|
||||
|
||||
if (dt.Scope == DocumentTemplate.DocumentTemplateScopes.Job)
|
||||
{
|
||||
// Write Job Log
|
||||
|
||||
Job j = (Job)Data;
|
||||
JobLog jl = new JobLog()
|
||||
{
|
||||
JobId = j.Id,
|
||||
TechUserId = CreatorUser.Id,
|
||||
Timestamp = DateTime.Now
|
||||
};
|
||||
jl.Comments = string.Format("Document Generated{0}{1} [{2}]", Environment.NewLine, dt.Description, dt.Id);
|
||||
dbContext.JobLogs.Add(jl);
|
||||
}
|
||||
|
||||
pdfGeneratedStream.Position = 0;
|
||||
return pdfGeneratedStream;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,471 +1,471 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using Disco.BI.DocumentTemplateBI.Importer;
|
||||
using Disco.BI.DocumentTemplateBI;
|
||||
using System.Drawing.Drawing2D;
|
||||
using com.google.zxing;
|
||||
using com.google.zxing.multi.qrcode;
|
||||
using Disco.Data.Repository;
|
||||
using System.Web.Caching;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using System.Collections;
|
||||
using com.google.zxing.common;
|
||||
using BitMiracle.LibTiff.Classic;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
public static class PdfImporter
|
||||
{
|
||||
|
||||
private class DetectImageResult : IDisposable
|
||||
{
|
||||
public Result Result { get; set; }
|
||||
public Point ResultOffset { get; set; }
|
||||
public double ResultScale { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do Nothing; yet...
|
||||
}
|
||||
}
|
||||
|
||||
private class DetectPageResult : IDisposable
|
||||
{
|
||||
public int PageNumber { get; set; }
|
||||
public DocumentUniqueIdentifier DetectedIdentifier { get; set; }
|
||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage ThumbnailImage { get; set; }
|
||||
public MemoryStream AttachmentThumbnailImage { get; set; }
|
||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage UndetectedPageImage { get; set; }
|
||||
|
||||
public void DrawThumbnailImageResult(DetectImageResult Result, Image DetectedImage)
|
||||
{
|
||||
if (Result.Result.ResultPoints.Length == 4)
|
||||
{ // Draw Square on Thumbnail
|
||||
using (Graphics thumbnailGraphics = Graphics.FromImage(ThumbnailImage.Montage))
|
||||
{
|
||||
var thumbnailOffset = ThumbnailImage.MontageSourceImageOffsets[DetectedImage];
|
||||
|
||||
var linePoints = Result.Result.ResultPoints.Select(p => new Point((int)(thumbnailOffset + ((Result.ResultOffset.X + p.X) * Result.ResultScale * ThumbnailImage.MontageScale)), (int)((p.Y + Result.ResultOffset.Y) * Result.ResultScale * ThumbnailImage.MontageScale))).ToArray();
|
||||
using (GraphicsPath graphicsPath = new GraphicsPath())
|
||||
{
|
||||
for (int linePointIndex = 0; linePointIndex < (linePoints.Length - 1); linePointIndex++)
|
||||
graphicsPath.AddLine(linePoints[linePointIndex], linePoints[linePointIndex + 1]);
|
||||
graphicsPath.AddLine(linePoints[linePoints.Length - 1], linePoints[0]);
|
||||
using (SolidBrush graphicsBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
|
||||
thumbnailGraphics.FillPath(graphicsBrush, graphicsPath);
|
||||
using (Pen graphicsPen = new Pen(Color.FromArgb(200, 255, 0, 0), 2))
|
||||
thumbnailGraphics.DrawPath(graphicsPen, graphicsPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (ThumbnailImage != null)
|
||||
{
|
||||
ThumbnailImage.Dispose();
|
||||
ThumbnailImage = null;
|
||||
}
|
||||
if (AttachmentThumbnailImage != null)
|
||||
{
|
||||
AttachmentThumbnailImage.Dispose();
|
||||
AttachmentThumbnailImage = null;
|
||||
}
|
||||
if (UndetectedPageImage != null)
|
||||
{
|
||||
UndetectedPageImage.Dispose();
|
||||
UndetectedPageImage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static DetectImageResult DetectImage(DiscoDataContext dbContext, Bitmap pageImageOriginal, string SessionId, IEnumerable<DocumentTemplate> detectDocumentTemplates)
|
||||
{
|
||||
Bitmap pageImage = pageImageOriginal;
|
||||
double pageImageModifiedScale = 1;
|
||||
|
||||
try
|
||||
{
|
||||
// Resize if Resolution > 80; Set to 72 Dpi
|
||||
if (pageImage.HorizontalResolution > 80 || pageImage.VerticalResolution > 80)
|
||||
{
|
||||
pageImageModifiedScale = pageImage.HorizontalResolution / 72;
|
||||
int newWidth = (int)((72 / pageImage.HorizontalResolution) * pageImage.Width);
|
||||
int newHeight = (int)((72 / pageImage.VerticalResolution) * pageImage.Height);
|
||||
pageImage = pageImage.ResizeImage(newWidth, newHeight);
|
||||
}
|
||||
|
||||
Result zxingResult = default(Result);
|
||||
Point zxingResultOffset = Point.Empty;
|
||||
QRCodeMultiReader zxingMfr = new QRCodeMultiReader();
|
||||
Hashtable zxingMfrHints = new Hashtable();
|
||||
zxingMfrHints.Add(DecodeHintType.TRY_HARDER, true);
|
||||
// Look in 'Known' locations
|
||||
foreach (DocumentTemplate dt in detectDocumentTemplates)
|
||||
{
|
||||
var locationBag = dt.QRCodeLocations(dbContext);
|
||||
foreach (var location in locationBag)
|
||||
{
|
||||
System.Drawing.Rectangle region = new Rectangle(
|
||||
(int)(pageImage.Width * location.Left),
|
||||
(int)(pageImage.Width * location.Top),
|
||||
(int)(pageImage.Width * location.Width),
|
||||
(int)(pageImage.Height * location.Height));
|
||||
RGBLuminanceSource zxingSource;
|
||||
using (Bitmap pageImageRegion = new Bitmap(region.Width, region.Height))
|
||||
{
|
||||
using (Graphics pageImageRegionGraphics = Graphics.FromImage(pageImageRegion))
|
||||
{
|
||||
pageImageRegionGraphics.DrawImage(pageImage, 0, 0, region, GraphicsUnit.Pixel);
|
||||
}
|
||||
zxingSource = new RGBLuminanceSource(pageImageRegion, region.Width, region.Height);
|
||||
}
|
||||
var zxingHB = new HybridBinarizer(zxingSource);
|
||||
var zxingBB = new BinaryBitmap(zxingHB);
|
||||
try
|
||||
{
|
||||
zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
||||
zxingResultOffset = region.Location;
|
||||
break;
|
||||
}
|
||||
catch (ReaderException)
|
||||
{
|
||||
// Ignore Location Errors
|
||||
}
|
||||
}
|
||||
if (zxingResult != null)
|
||||
break;
|
||||
}
|
||||
if (zxingResult == null)
|
||||
{
|
||||
// Not found with 'known' locations
|
||||
// Try whole image
|
||||
var zxingSource = new RGBLuminanceSource(pageImage, pageImage.Width, pageImage.Height);
|
||||
var zxingHB = new HybridBinarizer(zxingSource);
|
||||
var zxingBB = new BinaryBitmap(zxingHB);
|
||||
try
|
||||
{
|
||||
zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
||||
}
|
||||
catch (ReaderException)
|
||||
{
|
||||
// Ignore Errors
|
||||
}
|
||||
}
|
||||
|
||||
if (zxingResult != null)
|
||||
return new DetectImageResult() { Result = zxingResult, ResultOffset = zxingResultOffset, ResultScale = pageImageModifiedScale };
|
||||
else
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pageImageOriginal != pageImage)
|
||||
pageImage.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static DetectPageResult DetectPage(DiscoDataContext dbContext, PdfReader pdfReader, int PageNumber, string SessionId, string DataStoreSessionCacheLocation, IEnumerable<DocumentTemplate> detectDocumentTemplates)
|
||||
{
|
||||
DetectPageResult result = new DetectPageResult() { PageNumber = PageNumber };
|
||||
|
||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, 10, "Loading Page Images");
|
||||
|
||||
using (DisposableImageCollection pageImages = pdfReader.PdfPageImages(PageNumber))
|
||||
{
|
||||
if (pageImages.Count > 0)
|
||||
{
|
||||
result.ThumbnailImage = pageImages.BuildImageMontage(256, 256);
|
||||
var pageThumbnailFilename = Path.Combine(DataStoreSessionCacheLocation, string.Format("{0}-{1}", SessionId, PageNumber));
|
||||
|
||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
||||
|
||||
double pageProgressInterval = 90 / pageImages.Count;
|
||||
|
||||
foreach (var pageImageOriginal in pageImages)
|
||||
{
|
||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, (int)(10 + (pageProgressInterval * pageImages.IndexOf(pageImageOriginal))), String.Format("Processing Page Image {0} of {1}", pageImages.IndexOf(pageImageOriginal) + 1, pageImages.Count));
|
||||
|
||||
using (var zxingResult = DetectImage(dbContext, pageImageOriginal, SessionId, detectDocumentTemplates))
|
||||
{
|
||||
if (zxingResult != null)
|
||||
{
|
||||
if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(zxingResult.Result.Text))
|
||||
{
|
||||
result.DrawThumbnailImageResult(zxingResult, pageImageOriginal);
|
||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
||||
|
||||
result.AttachmentThumbnailImage = new MemoryStream();
|
||||
using (var attachmentThumbImage = pageImages.BuildImageMontage(48, 48, true))
|
||||
{
|
||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
||||
attachmentThumbImage.Montage.EmbedIconOverlay(mimeTypeIcon);
|
||||
attachmentThumbImage.Montage.SaveJpg(95, result.AttachmentThumbnailImage);
|
||||
}
|
||||
|
||||
result.DetectedIdentifier = new DocumentUniqueIdentifier(zxingResult.Result.Text, PageNumber.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Page Unassigned
|
||||
result.UndetectedPageImage = pageImages.BuildImageMontage(700, 700);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string SessionId, Cache HttpCache)
|
||||
{
|
||||
var dataStoreUnassignedLocation = DataStore.CreateLocation(dbContext, "DocumentDropBox_Unassigned");
|
||||
|
||||
DocumentImporterLog.LogImportProgress(SessionId, 0, "Reading File");
|
||||
|
||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
var pdfReader = new PdfReader(fs);
|
||||
|
||||
var pdfPagesAssigned = new Dictionary<int, Tuple<DocumentUniqueIdentifier, byte[]>>();
|
||||
|
||||
var dataStoreSessionPagesCacheLocation = DataStore.CreateLocation(dbContext, "Cache\\DocumentDropBox_SessionPages");
|
||||
var detectDocumentTemplates = dbContext.DocumentTemplates.ToArray();
|
||||
|
||||
double progressInterval = 70 / pdfReader.NumberOfPages;
|
||||
|
||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(PageNumber * progressInterval), string.Format("Processing Page {0} of {1}", PageNumber, pdfReader.NumberOfPages));
|
||||
DocumentImporterLog.LogImportPageStarting(SessionId, PageNumber);
|
||||
|
||||
using (var pageResult = DetectPage(dbContext, pdfReader, PageNumber, SessionId, dataStoreSessionPagesCacheLocation, detectDocumentTemplates))
|
||||
{
|
||||
if (pageResult.DetectedIdentifier != null)
|
||||
{
|
||||
var docId = pageResult.DetectedIdentifier;
|
||||
pdfPagesAssigned.Add(PageNumber, new Tuple<DocumentUniqueIdentifier, byte[]>(docId, pageResult.AttachmentThumbnailImage.ToArray()));
|
||||
|
||||
docId.LoadComponents(dbContext);
|
||||
DocumentImporterLog.LogImportPageDetected(SessionId, PageNumber, docId.DocumentUniqueId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undetected Page - Write Preview-Images while still in Memory
|
||||
DocumentImporterLog.LogImportPageUndetected(SessionId, PageNumber);
|
||||
|
||||
// Thumbnail:
|
||||
string unassignedImageThumbnailFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}_thumbnail.png", SessionId, PageNumber));
|
||||
pageResult.ThumbnailImage.Montage.SavePng(unassignedImageThumbnailFilename);
|
||||
// Large Preview
|
||||
string unassignedImageFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.jpg", SessionId, PageNumber));
|
||||
pageResult.UndetectedPageImage.Montage.SaveJpg(90, unassignedImageFilename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write out Assigned Documents
|
||||
var assignedDocuments = pdfPagesAssigned.GroupBy(u => u.Value.Item1.DocumentUniqueId).ToList();
|
||||
if (assignedDocuments.Count > 0)
|
||||
{
|
||||
progressInterval = 20 / assignedDocuments.Count;
|
||||
|
||||
foreach (var documentPortion in assignedDocuments)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(70 + (assignedDocuments.IndexOf(documentPortion) * progressInterval)), string.Format("Importing Documents {0} of {1}", assignedDocuments.IndexOf(documentPortion) + 1, assignedDocuments.Count));
|
||||
|
||||
var documentPortionInfo = documentPortion.First().Value;
|
||||
var documentPortionIdentifier = documentPortionInfo.Item1;
|
||||
var documentPortionThumbnail = documentPortionInfo.Item2;
|
||||
|
||||
if (!documentPortionIdentifier.LoadComponents(dbContext))
|
||||
{
|
||||
// Unknown Document Unique Id
|
||||
foreach (var dp in documentPortion)
|
||||
{
|
||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
||||
if (pdfPagesAssigned.ContainsKey(tag))
|
||||
pdfPagesAssigned.Remove(tag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (MemoryStream msBuilder = new MemoryStream())
|
||||
{
|
||||
var pdfDoc = new iTextSharp.text.Document();
|
||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
||||
|
||||
pdfDoc.Open();
|
||||
pdfCopy.CloseStream = false;
|
||||
|
||||
foreach (var dp in documentPortion.OrderBy(dg => dg.Value.Item1.Page))
|
||||
{
|
||||
var pageSize = pdfReader.GetPageSizeWithRotation(dp.Key);
|
||||
var page = pdfCopy.GetImportedPage(pdfReader, dp.Key);
|
||||
|
||||
pdfDoc.SetPageSize(pageSize);
|
||||
pdfDoc.NewPage();
|
||||
|
||||
pdfCopy.AddPage(page);
|
||||
}
|
||||
|
||||
pdfDoc.Close();
|
||||
pdfCopy.Close();
|
||||
|
||||
msBuilder.Position = 0;
|
||||
|
||||
var attachmentSuccess = documentPortionIdentifier.ImportPdfAttachment(dbContext, msBuilder, documentPortionThumbnail);
|
||||
|
||||
if (!attachmentSuccess)
|
||||
{ // Unable to add Attachment
|
||||
foreach (var dp in documentPortion)
|
||||
{
|
||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
||||
if (pdfPagesAssigned.ContainsKey(tag))
|
||||
pdfPagesAssigned.Remove(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Write out Unassigned Pages
|
||||
List<int> pdfPagesUnassigned = new List<int>();
|
||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
||||
if (!pdfPagesAssigned.ContainsKey(PageNumber))
|
||||
pdfPagesUnassigned.Add(PageNumber);
|
||||
if (pdfPagesUnassigned.Count > 0)
|
||||
{
|
||||
progressInterval = 10 / pdfPagesUnassigned.Count;
|
||||
//dataStoreUnassignedLocation
|
||||
foreach (var PageNumber in pdfPagesUnassigned)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(90 + (pdfPagesUnassigned.IndexOf(PageNumber) * progressInterval)), string.Format("Processing Undetected Documents {0} of {1}", pdfPagesUnassigned.IndexOf(PageNumber) + 1, pdfPagesUnassigned.Count));
|
||||
|
||||
using (MemoryStream msBuilder = new MemoryStream())
|
||||
{
|
||||
var pdfDoc = new iTextSharp.text.Document();
|
||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
||||
|
||||
pdfDoc.Open();
|
||||
pdfCopy.CloseStream = false;
|
||||
|
||||
var pageSize = pdfReader.GetPageSizeWithRotation(PageNumber);
|
||||
var page = pdfCopy.GetImportedPage(pdfReader, PageNumber);
|
||||
pdfDoc.SetPageSize(pageSize);
|
||||
pdfDoc.NewPage();
|
||||
|
||||
pdfCopy.AddPage(page);
|
||||
pdfDoc.Close();
|
||||
pdfCopy.Close();
|
||||
|
||||
File.WriteAllBytes(Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.pdf", SessionId, PageNumber)), msBuilder.ToArray());
|
||||
|
||||
DocumentImporterLog.LogImportPageUndetectedStored(SessionId, PageNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DocumentImporterLog.LogImportProgress(SessionId, 100, "Finished Importing Document");
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string DocumentTemplateId, string DataId, string UserId, DateTime Timestamp)
|
||||
{
|
||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
DocumentUniqueIdentifier identifier = new DocumentUniqueIdentifier(DocumentTemplateId, DataId, UserId, Timestamp);
|
||||
identifier.LoadComponents(dbContext);
|
||||
return identifier.ImportPdfAttachment(dbContext, fs, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static DisposableImageCollection GetPageImages(PdfReader pdfReader, int PageNumber)
|
||||
{
|
||||
var pageImages = new DisposableImageCollection();
|
||||
|
||||
var pdfPage = pdfReader.GetPageN(PageNumber);
|
||||
PdfDictionary pdfPageResouces = (PdfDictionary)((PdfDictionary)pdfPage.GetDirectObject(PdfName.RESOURCES)).GetDirectObject(PdfName.XOBJECT);
|
||||
|
||||
foreach (var pdfResKey in pdfPageResouces.Keys)
|
||||
{
|
||||
var pdfRes = pdfPageResouces.GetDirectObject(pdfResKey);
|
||||
if (pdfRes.IsStream())
|
||||
{
|
||||
var pdfResStream = (PdfStream)pdfRes;
|
||||
var pdfResSubType = pdfResStream.Get(PdfName.SUBTYPE);
|
||||
if (pdfResSubType != null && pdfResSubType == PdfName.IMAGE)
|
||||
{
|
||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.CCITTFAXDECODE)
|
||||
{ // TIFF
|
||||
// Try Using GDI+ for TIFF...
|
||||
var width = ((PdfNumber)(pdfResStream.Get(PdfName.WIDTH))).IntValue;
|
||||
var height = ((PdfNumber)(pdfResStream.Get(PdfName.HEIGHT))).IntValue;
|
||||
var bpc = ((PdfNumber)(pdfResStream.Get(PdfName.BITSPERCOMPONENT))).IntValue;
|
||||
|
||||
var compressionMethod = Compression.CCITTFAX3;
|
||||
|
||||
var decodeParams = pdfResStream.GetAsDict(PdfName.DECODEPARMS);
|
||||
if (decodeParams != null && decodeParams.Contains(PdfName.K) && decodeParams.GetAsNumber(PdfName.K).IntValue < 0)
|
||||
compressionMethod = Compression.CCITTFAX4;
|
||||
|
||||
using (MemoryStream tiffStream = PdfToTiffStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream), width, height, bpc, compressionMethod))
|
||||
{
|
||||
pageImages.Add((Bitmap)Bitmap.FromStream(tiffStream));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.DCTDECODE)
|
||||
{ // JPG
|
||||
using (MemoryStream jpgStream = new MemoryStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream)))
|
||||
{
|
||||
pageImages.Add((Bitmap)Bitmap.FromStream(jpgStream, true, true));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pageImages;
|
||||
}
|
||||
|
||||
private static MemoryStream PdfToTiffStream(byte[] PdfStream, int Width, int Height, int BitsPerComponent, Compression CompressionMethod)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
|
||||
Tiff tif = Tiff.ClientOpen("in-memory", "w", ms, new TiffStream());
|
||||
tif.SetField(TiffTag.IMAGEWIDTH, Width);
|
||||
tif.SetField(TiffTag.IMAGELENGTH, Height);
|
||||
tif.SetField(TiffTag.COMPRESSION, CompressionMethod);
|
||||
tif.SetField(TiffTag.BITSPERSAMPLE, BitsPerComponent);
|
||||
tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
|
||||
tif.WriteRawStrip(0, PdfStream, PdfStream.Length);
|
||||
tif.Flush();
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using iTextSharp.text.pdf;
|
||||
using System.IO;
|
||||
using System.Drawing;
|
||||
using Disco.BI.DocumentTemplateBI.Importer;
|
||||
using Disco.BI.DocumentTemplateBI;
|
||||
using System.Drawing.Drawing2D;
|
||||
using com.google.zxing;
|
||||
using com.google.zxing.multi.qrcode;
|
||||
using Disco.Data.Repository;
|
||||
using System.Web.Caching;
|
||||
using Disco.BI.Extensions;
|
||||
using Disco.Models.Repository;
|
||||
using System.Collections;
|
||||
using com.google.zxing.common;
|
||||
using BitMiracle.LibTiff.Classic;
|
||||
|
||||
namespace Disco.BI.Interop.Pdf
|
||||
{
|
||||
public static class PdfImporter
|
||||
{
|
||||
|
||||
private class DetectImageResult : IDisposable
|
||||
{
|
||||
public Result Result { get; set; }
|
||||
public Point ResultOffset { get; set; }
|
||||
public double ResultScale { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do Nothing; yet...
|
||||
}
|
||||
}
|
||||
|
||||
private class DetectPageResult : IDisposable
|
||||
{
|
||||
public int PageNumber { get; set; }
|
||||
public DocumentUniqueIdentifier DetectedIdentifier { get; set; }
|
||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage ThumbnailImage { get; set; }
|
||||
public MemoryStream AttachmentThumbnailImage { get; set; }
|
||||
public Disco.BI.Extensions.UtilityExtensions.ImageMontage UndetectedPageImage { get; set; }
|
||||
|
||||
public void DrawThumbnailImageResult(DetectImageResult Result, Image DetectedImage)
|
||||
{
|
||||
if (Result.Result.ResultPoints.Length == 4)
|
||||
{ // Draw Square on Thumbnail
|
||||
using (Graphics thumbnailGraphics = Graphics.FromImage(ThumbnailImage.Montage))
|
||||
{
|
||||
var thumbnailOffset = ThumbnailImage.MontageSourceImageOffsets[DetectedImage];
|
||||
|
||||
var linePoints = Result.Result.ResultPoints.Select(p => new Point((int)(thumbnailOffset + ((Result.ResultOffset.X + p.X) * Result.ResultScale * ThumbnailImage.MontageScale)), (int)((p.Y + Result.ResultOffset.Y) * Result.ResultScale * ThumbnailImage.MontageScale))).ToArray();
|
||||
using (GraphicsPath graphicsPath = new GraphicsPath())
|
||||
{
|
||||
for (int linePointIndex = 0; linePointIndex < (linePoints.Length - 1); linePointIndex++)
|
||||
graphicsPath.AddLine(linePoints[linePointIndex], linePoints[linePointIndex + 1]);
|
||||
graphicsPath.AddLine(linePoints[linePoints.Length - 1], linePoints[0]);
|
||||
using (SolidBrush graphicsBrush = new SolidBrush(Color.FromArgb(128, 255, 0, 0)))
|
||||
thumbnailGraphics.FillPath(graphicsBrush, graphicsPath);
|
||||
using (Pen graphicsPen = new Pen(Color.FromArgb(200, 255, 0, 0), 2))
|
||||
thumbnailGraphics.DrawPath(graphicsPen, graphicsPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (ThumbnailImage != null)
|
||||
{
|
||||
ThumbnailImage.Dispose();
|
||||
ThumbnailImage = null;
|
||||
}
|
||||
if (AttachmentThumbnailImage != null)
|
||||
{
|
||||
AttachmentThumbnailImage.Dispose();
|
||||
AttachmentThumbnailImage = null;
|
||||
}
|
||||
if (UndetectedPageImage != null)
|
||||
{
|
||||
UndetectedPageImage.Dispose();
|
||||
UndetectedPageImage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static DetectImageResult DetectImage(DiscoDataContext dbContext, Bitmap pageImageOriginal, string SessionId, IEnumerable<DocumentTemplate> detectDocumentTemplates)
|
||||
{
|
||||
Bitmap pageImage = pageImageOriginal;
|
||||
double pageImageModifiedScale = 1;
|
||||
|
||||
try
|
||||
{
|
||||
// Resize if Resolution > 80; Set to 72 Dpi
|
||||
if (pageImage.HorizontalResolution > 80 || pageImage.VerticalResolution > 80)
|
||||
{
|
||||
pageImageModifiedScale = pageImage.HorizontalResolution / 72;
|
||||
int newWidth = (int)((72 / pageImage.HorizontalResolution) * pageImage.Width);
|
||||
int newHeight = (int)((72 / pageImage.VerticalResolution) * pageImage.Height);
|
||||
pageImage = pageImage.ResizeImage(newWidth, newHeight);
|
||||
}
|
||||
|
||||
Result zxingResult = default(Result);
|
||||
Point zxingResultOffset = Point.Empty;
|
||||
QRCodeMultiReader zxingMfr = new QRCodeMultiReader();
|
||||
Hashtable zxingMfrHints = new Hashtable();
|
||||
zxingMfrHints.Add(DecodeHintType.TRY_HARDER, true);
|
||||
// Look in 'Known' locations
|
||||
foreach (DocumentTemplate dt in detectDocumentTemplates)
|
||||
{
|
||||
var locationBag = dt.QRCodeLocations(dbContext);
|
||||
foreach (var location in locationBag)
|
||||
{
|
||||
System.Drawing.Rectangle region = new Rectangle(
|
||||
(int)(pageImage.Width * location.Left),
|
||||
(int)(pageImage.Width * location.Top),
|
||||
(int)(pageImage.Width * location.Width),
|
||||
(int)(pageImage.Height * location.Height));
|
||||
RGBLuminanceSource zxingSource;
|
||||
using (Bitmap pageImageRegion = new Bitmap(region.Width, region.Height))
|
||||
{
|
||||
using (Graphics pageImageRegionGraphics = Graphics.FromImage(pageImageRegion))
|
||||
{
|
||||
pageImageRegionGraphics.DrawImage(pageImage, 0, 0, region, GraphicsUnit.Pixel);
|
||||
}
|
||||
zxingSource = new RGBLuminanceSource(pageImageRegion, region.Width, region.Height);
|
||||
}
|
||||
var zxingHB = new HybridBinarizer(zxingSource);
|
||||
var zxingBB = new BinaryBitmap(zxingHB);
|
||||
try
|
||||
{
|
||||
zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
||||
zxingResultOffset = region.Location;
|
||||
break;
|
||||
}
|
||||
catch (ReaderException)
|
||||
{
|
||||
// Ignore Location Errors
|
||||
}
|
||||
}
|
||||
if (zxingResult != null)
|
||||
break;
|
||||
}
|
||||
if (zxingResult == null)
|
||||
{
|
||||
// Not found with 'known' locations
|
||||
// Try whole image
|
||||
var zxingSource = new RGBLuminanceSource(pageImage, pageImage.Width, pageImage.Height);
|
||||
var zxingHB = new HybridBinarizer(zxingSource);
|
||||
var zxingBB = new BinaryBitmap(zxingHB);
|
||||
try
|
||||
{
|
||||
zxingResult = zxingMfr.decode(zxingBB, zxingMfrHints);
|
||||
}
|
||||
catch (ReaderException)
|
||||
{
|
||||
// Ignore Errors
|
||||
}
|
||||
}
|
||||
|
||||
if (zxingResult != null)
|
||||
return new DetectImageResult() { Result = zxingResult, ResultOffset = zxingResultOffset, ResultScale = pageImageModifiedScale };
|
||||
else
|
||||
return null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pageImageOriginal != pageImage)
|
||||
pageImage.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static DetectPageResult DetectPage(DiscoDataContext dbContext, PdfReader pdfReader, int PageNumber, string SessionId, string DataStoreSessionCacheLocation, IEnumerable<DocumentTemplate> detectDocumentTemplates)
|
||||
{
|
||||
DetectPageResult result = new DetectPageResult() { PageNumber = PageNumber };
|
||||
|
||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, 10, "Loading Page Images");
|
||||
|
||||
using (DisposableImageCollection pageImages = pdfReader.PdfPageImages(PageNumber))
|
||||
{
|
||||
if (pageImages.Count > 0)
|
||||
{
|
||||
result.ThumbnailImage = pageImages.BuildImageMontage(256, 256);
|
||||
var pageThumbnailFilename = Path.Combine(DataStoreSessionCacheLocation, string.Format("{0}-{1}", SessionId, PageNumber));
|
||||
|
||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
||||
|
||||
double pageProgressInterval = 90 / pageImages.Count;
|
||||
|
||||
foreach (var pageImageOriginal in pageImages)
|
||||
{
|
||||
DocumentImporterLog.LogImportPageProgress(SessionId, PageNumber, (int)(10 + (pageProgressInterval * pageImages.IndexOf(pageImageOriginal))), String.Format("Processing Page Image {0} of {1}", pageImages.IndexOf(pageImageOriginal) + 1, pageImages.Count));
|
||||
|
||||
using (var zxingResult = DetectImage(dbContext, pageImageOriginal, SessionId, detectDocumentTemplates))
|
||||
{
|
||||
if (zxingResult != null)
|
||||
{
|
||||
if (DocumentUniqueIdentifier.IsDocumentUniqueIdentifier(zxingResult.Result.Text))
|
||||
{
|
||||
result.DrawThumbnailImageResult(zxingResult, pageImageOriginal);
|
||||
result.ThumbnailImage.Montage.SavePng(pageThumbnailFilename);
|
||||
DocumentImporterLog.LogImportPageImageUpdate(SessionId, PageNumber);
|
||||
|
||||
result.AttachmentThumbnailImage = new MemoryStream();
|
||||
using (var attachmentThumbImage = pageImages.BuildImageMontage(48, 48, true))
|
||||
{
|
||||
using (Image mimeTypeIcon = Disco.Properties.Resources.MimeType_pdf16)
|
||||
attachmentThumbImage.Montage.EmbedIconOverlay(mimeTypeIcon);
|
||||
attachmentThumbImage.Montage.SaveJpg(95, result.AttachmentThumbnailImage);
|
||||
}
|
||||
|
||||
result.DetectedIdentifier = new DocumentUniqueIdentifier(zxingResult.Result.Text, PageNumber.ToString());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Page Unassigned
|
||||
result.UndetectedPageImage = pageImages.BuildImageMontage(700, 700);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string SessionId, Cache HttpCache)
|
||||
{
|
||||
var dataStoreUnassignedLocation = DataStore.CreateLocation(dbContext, "DocumentDropBox_Unassigned");
|
||||
|
||||
DocumentImporterLog.LogImportProgress(SessionId, 0, "Reading File");
|
||||
|
||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
var pdfReader = new PdfReader(fs);
|
||||
|
||||
var pdfPagesAssigned = new Dictionary<int, Tuple<DocumentUniqueIdentifier, byte[]>>();
|
||||
|
||||
var dataStoreSessionPagesCacheLocation = DataStore.CreateLocation(dbContext, "Cache\\DocumentDropBox_SessionPages");
|
||||
var detectDocumentTemplates = dbContext.DocumentTemplates.ToArray();
|
||||
|
||||
double progressInterval = 70 / pdfReader.NumberOfPages;
|
||||
|
||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(PageNumber * progressInterval), string.Format("Processing Page {0} of {1}", PageNumber, pdfReader.NumberOfPages));
|
||||
DocumentImporterLog.LogImportPageStarting(SessionId, PageNumber);
|
||||
|
||||
using (var pageResult = DetectPage(dbContext, pdfReader, PageNumber, SessionId, dataStoreSessionPagesCacheLocation, detectDocumentTemplates))
|
||||
{
|
||||
if (pageResult.DetectedIdentifier != null)
|
||||
{
|
||||
var docId = pageResult.DetectedIdentifier;
|
||||
pdfPagesAssigned.Add(PageNumber, new Tuple<DocumentUniqueIdentifier, byte[]>(docId, pageResult.AttachmentThumbnailImage.ToArray()));
|
||||
|
||||
docId.LoadComponents(dbContext);
|
||||
DocumentImporterLog.LogImportPageDetected(SessionId, PageNumber, docId.DocumentUniqueId, docId.DocumentTemplate.Description, docId.DocumentTemplate.Scope, docId.DataId, docId.DataDescription);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undetected Page - Write Preview-Images while still in Memory
|
||||
DocumentImporterLog.LogImportPageUndetected(SessionId, PageNumber);
|
||||
|
||||
// Thumbnail:
|
||||
string unassignedImageThumbnailFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}_thumbnail.png", SessionId, PageNumber));
|
||||
pageResult.ThumbnailImage.Montage.SavePng(unassignedImageThumbnailFilename);
|
||||
// Large Preview
|
||||
string unassignedImageFilename = Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.jpg", SessionId, PageNumber));
|
||||
pageResult.UndetectedPageImage.Montage.SaveJpg(90, unassignedImageFilename);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Write out Assigned Documents
|
||||
var assignedDocuments = pdfPagesAssigned.GroupBy(u => u.Value.Item1.DocumentUniqueId).ToList();
|
||||
if (assignedDocuments.Count > 0)
|
||||
{
|
||||
progressInterval = 20 / assignedDocuments.Count;
|
||||
|
||||
foreach (var documentPortion in assignedDocuments)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(70 + (assignedDocuments.IndexOf(documentPortion) * progressInterval)), string.Format("Importing Documents {0} of {1}", assignedDocuments.IndexOf(documentPortion) + 1, assignedDocuments.Count));
|
||||
|
||||
var documentPortionInfo = documentPortion.First().Value;
|
||||
var documentPortionIdentifier = documentPortionInfo.Item1;
|
||||
var documentPortionThumbnail = documentPortionInfo.Item2;
|
||||
|
||||
if (!documentPortionIdentifier.LoadComponents(dbContext))
|
||||
{
|
||||
// Unknown Document Unique Id
|
||||
foreach (var dp in documentPortion)
|
||||
{
|
||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
||||
if (pdfPagesAssigned.ContainsKey(tag))
|
||||
pdfPagesAssigned.Remove(tag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (MemoryStream msBuilder = new MemoryStream())
|
||||
{
|
||||
var pdfDoc = new iTextSharp.text.Document();
|
||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
||||
|
||||
pdfDoc.Open();
|
||||
pdfCopy.CloseStream = false;
|
||||
|
||||
foreach (var dp in documentPortion.OrderBy(dg => dg.Value.Item1.Page))
|
||||
{
|
||||
var pageSize = pdfReader.GetPageSizeWithRotation(dp.Key);
|
||||
var page = pdfCopy.GetImportedPage(pdfReader, dp.Key);
|
||||
|
||||
pdfDoc.SetPageSize(pageSize);
|
||||
pdfDoc.NewPage();
|
||||
|
||||
pdfCopy.AddPage(page);
|
||||
}
|
||||
|
||||
pdfDoc.Close();
|
||||
pdfCopy.Close();
|
||||
|
||||
msBuilder.Position = 0;
|
||||
|
||||
var attachmentSuccess = documentPortionIdentifier.ImportPdfAttachment(dbContext, msBuilder, documentPortionThumbnail);
|
||||
|
||||
if (!attachmentSuccess)
|
||||
{ // Unable to add Attachment
|
||||
foreach (var dp in documentPortion)
|
||||
{
|
||||
var tag = int.Parse(dp.Value.Item1.Tag);
|
||||
if (pdfPagesAssigned.ContainsKey(tag))
|
||||
pdfPagesAssigned.Remove(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Write out Unassigned Pages
|
||||
List<int> pdfPagesUnassigned = new List<int>();
|
||||
for (int PageNumber = 1; PageNumber <= pdfReader.NumberOfPages; PageNumber++)
|
||||
if (!pdfPagesAssigned.ContainsKey(PageNumber))
|
||||
pdfPagesUnassigned.Add(PageNumber);
|
||||
if (pdfPagesUnassigned.Count > 0)
|
||||
{
|
||||
progressInterval = 10 / pdfPagesUnassigned.Count;
|
||||
//dataStoreUnassignedLocation
|
||||
foreach (var PageNumber in pdfPagesUnassigned)
|
||||
{
|
||||
DocumentImporterLog.LogImportProgress(SessionId, (int)(90 + (pdfPagesUnassigned.IndexOf(PageNumber) * progressInterval)), string.Format("Processing Undetected Documents {0} of {1}", pdfPagesUnassigned.IndexOf(PageNumber) + 1, pdfPagesUnassigned.Count));
|
||||
|
||||
using (MemoryStream msBuilder = new MemoryStream())
|
||||
{
|
||||
var pdfDoc = new iTextSharp.text.Document();
|
||||
var pdfCopy = new PdfCopy(pdfDoc, msBuilder);
|
||||
|
||||
pdfDoc.Open();
|
||||
pdfCopy.CloseStream = false;
|
||||
|
||||
var pageSize = pdfReader.GetPageSizeWithRotation(PageNumber);
|
||||
var page = pdfCopy.GetImportedPage(pdfReader, PageNumber);
|
||||
pdfDoc.SetPageSize(pageSize);
|
||||
pdfDoc.NewPage();
|
||||
|
||||
pdfCopy.AddPage(page);
|
||||
pdfDoc.Close();
|
||||
pdfCopy.Close();
|
||||
|
||||
File.WriteAllBytes(Path.Combine(dataStoreUnassignedLocation, string.Format("{0}_{1}.pdf", SessionId, PageNumber)), msBuilder.ToArray());
|
||||
|
||||
DocumentImporterLog.LogImportPageUndetectedStored(SessionId, PageNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DocumentImporterLog.LogImportProgress(SessionId, 100, "Finished Importing Document");
|
||||
|
||||
return true;
|
||||
}
|
||||
public static bool ProcessPdfAttachment(string Filename, DiscoDataContext dbContext, string DocumentTemplateId, string DataId, string UserId, DateTime Timestamp)
|
||||
{
|
||||
using (FileStream fs = new FileStream(Filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
|
||||
{
|
||||
DocumentUniqueIdentifier identifier = new DocumentUniqueIdentifier(DocumentTemplateId, DataId, UserId, Timestamp);
|
||||
identifier.LoadComponents(dbContext);
|
||||
return identifier.ImportPdfAttachment(dbContext, fs, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static DisposableImageCollection GetPageImages(PdfReader pdfReader, int PageNumber)
|
||||
{
|
||||
var pageImages = new DisposableImageCollection();
|
||||
|
||||
var pdfPage = pdfReader.GetPageN(PageNumber);
|
||||
PdfDictionary pdfPageResouces = (PdfDictionary)((PdfDictionary)pdfPage.GetDirectObject(PdfName.RESOURCES)).GetDirectObject(PdfName.XOBJECT);
|
||||
|
||||
foreach (var pdfResKey in pdfPageResouces.Keys)
|
||||
{
|
||||
var pdfRes = pdfPageResouces.GetDirectObject(pdfResKey);
|
||||
if (pdfRes.IsStream())
|
||||
{
|
||||
var pdfResStream = (PdfStream)pdfRes;
|
||||
var pdfResSubType = pdfResStream.Get(PdfName.SUBTYPE);
|
||||
if (pdfResSubType != null && pdfResSubType == PdfName.IMAGE)
|
||||
{
|
||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.CCITTFAXDECODE)
|
||||
{ // TIFF
|
||||
// Try Using GDI+ for TIFF...
|
||||
var width = ((PdfNumber)(pdfResStream.Get(PdfName.WIDTH))).IntValue;
|
||||
var height = ((PdfNumber)(pdfResStream.Get(PdfName.HEIGHT))).IntValue;
|
||||
var bpc = ((PdfNumber)(pdfResStream.Get(PdfName.BITSPERCOMPONENT))).IntValue;
|
||||
|
||||
var compressionMethod = Compression.CCITTFAX3;
|
||||
|
||||
var decodeParams = pdfResStream.GetAsDict(PdfName.DECODEPARMS);
|
||||
if (decodeParams != null && decodeParams.Contains(PdfName.K) && decodeParams.GetAsNumber(PdfName.K).IntValue < 0)
|
||||
compressionMethod = Compression.CCITTFAX4;
|
||||
|
||||
using (MemoryStream tiffStream = PdfToTiffStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream), width, height, bpc, compressionMethod))
|
||||
{
|
||||
pageImages.Add((Bitmap)Bitmap.FromStream(tiffStream));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (pdfResStream.Get(PdfName.FILTER) == PdfName.DCTDECODE)
|
||||
{ // JPG
|
||||
using (MemoryStream jpgStream = new MemoryStream(PdfReader.GetStreamBytesRaw((PRStream)pdfResStream)))
|
||||
{
|
||||
pageImages.Add((Bitmap)Bitmap.FromStream(jpgStream, true, true));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pageImages;
|
||||
}
|
||||
|
||||
private static MemoryStream PdfToTiffStream(byte[] PdfStream, int Width, int Height, int BitsPerComponent, Compression CompressionMethod)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
|
||||
Tiff tif = Tiff.ClientOpen("in-memory", "w", ms, new TiffStream());
|
||||
tif.SetField(TiffTag.IMAGEWIDTH, Width);
|
||||
tif.SetField(TiffTag.IMAGELENGTH, Height);
|
||||
tif.SetField(TiffTag.COMPRESSION, CompressionMethod);
|
||||
tif.SetField(TiffTag.BITSPERSAMPLE, BitsPerComponent);
|
||||
tif.SetField(TiffTag.SAMPLESPERPIXEL, 1);
|
||||
tif.WriteRawStrip(0, PdfStream, PdfStream.Length);
|
||||
tif.Flush();
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Data.Repository;
|
||||
//using Quartz;
|
||||
|
||||
//namespace Disco.BI.Interop.PluginServices
|
||||
//{
|
||||
// interface IDiscoScheduledTask
|
||||
// {
|
||||
// void InitalizeScheduledTask(DiscoDataContext dbContext, IScheduler Scheduler);
|
||||
// }
|
||||
//}
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Data.Repository;
|
||||
//using Quartz;
|
||||
|
||||
//namespace Disco.BI.Interop.PluginServices
|
||||
//{
|
||||
// interface IDiscoScheduledTask
|
||||
// {
|
||||
// void InitalizeScheduledTask(DiscoDataContext dbContext, IScheduler Scheduler);
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Data.Repository;
|
||||
//using Quartz;
|
||||
|
||||
//namespace Disco.BI.Interop.PluginServices
|
||||
//{
|
||||
// public static class Utilities
|
||||
// {
|
||||
|
||||
// public static void InitalizeScheduledTasks(DiscoDataContext dbContext, ISchedulerFactory SchedulerFactory)
|
||||
// {
|
||||
|
||||
// var scheduler = SchedulerFactory.GetScheduler();
|
||||
|
||||
// // Discover IDiscoScheduledTasks (Only from Disco Assemblies)
|
||||
// var appDomain = AppDomain.CurrentDomain;
|
||||
|
||||
// var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
|
||||
// where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
|
||||
// from type in a.GetTypes()
|
||||
// where typeof(IDiscoScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
||||
// select type);
|
||||
// foreach (Type scheduledTaskType in scheduledTaskTypes)
|
||||
// {
|
||||
// IDiscoScheduledTask instance = (IDiscoScheduledTask)Activator.CreateInstance(scheduledTaskType);
|
||||
// try
|
||||
// {
|
||||
// instance.InitalizeScheduledTask(dbContext, scheduler);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// if (instance == null)
|
||||
// Logging.SystemLog.LogException("Initializing Scheduled Task; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", ex);
|
||||
// else
|
||||
// Logging.SystemLog.LogException(string.Format("Initializing Scheduled Task: '{0}'; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", instance.GetType().Name), ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Data.Repository;
|
||||
//using Quartz;
|
||||
|
||||
//namespace Disco.BI.Interop.PluginServices
|
||||
//{
|
||||
// public static class Utilities
|
||||
// {
|
||||
|
||||
// public static void InitalizeScheduledTasks(DiscoDataContext dbContext, ISchedulerFactory SchedulerFactory)
|
||||
// {
|
||||
|
||||
// var scheduler = SchedulerFactory.GetScheduler();
|
||||
|
||||
// // Discover IDiscoScheduledTasks (Only from Disco Assemblies)
|
||||
// var appDomain = AppDomain.CurrentDomain;
|
||||
|
||||
// var scheduledTaskTypes = (from a in appDomain.GetAssemblies()
|
||||
// where !a.GlobalAssemblyCache && !a.IsDynamic && a.FullName.StartsWith("Disco.", StringComparison.InvariantCultureIgnoreCase)
|
||||
// from type in a.GetTypes()
|
||||
// where typeof(IDiscoScheduledTask).IsAssignableFrom(type) && !type.IsAbstract
|
||||
// select type);
|
||||
// foreach (Type scheduledTaskType in scheduledTaskTypes)
|
||||
// {
|
||||
// IDiscoScheduledTask instance = (IDiscoScheduledTask)Activator.CreateInstance(scheduledTaskType);
|
||||
// try
|
||||
// {
|
||||
// instance.InitalizeScheduledTask(dbContext, scheduler);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// if (instance == null)
|
||||
// Logging.SystemLog.LogException("Initializing Scheduled Task; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", ex);
|
||||
// else
|
||||
// Logging.SystemLog.LogException(string.Format("Initializing Scheduled Task: '{0}'; Disco.BI.Interop.Plugins.Utilities.InitalizeScheduledTasks()", instance.GetType().Name), ex);
|
||||
// }
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SignalR;
|
||||
using SignalR.Hosting.AspNet;
|
||||
using SignalR.Infrastructure;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class UserHeldDevices : PersistentConnection
|
||||
{
|
||||
|
||||
internal static void UserJobUpdated(string JobUserId)
|
||||
{
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<UserHeldDevices>();
|
||||
if (connectionContext != null)
|
||||
connectionContext.Connection.Broadcast(JobUserId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using SignalR;
|
||||
using SignalR.Hosting.AspNet;
|
||||
using SignalR.Infrastructure;
|
||||
|
||||
namespace Disco.BI.Interop.SignalRHandlers
|
||||
{
|
||||
public class UserHeldDevices : PersistentConnection
|
||||
{
|
||||
|
||||
internal static void UserJobUpdated(string JobUserId)
|
||||
{
|
||||
var connectionManager = GlobalHost.ConnectionManager;
|
||||
var connectionContext = connectionManager.GetConnectionContext<UserHeldDevices>();
|
||||
if (connectionContext != null)
|
||||
connectionContext.Connection.Broadcast(JobUserId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user