-
-
Save msd-sal/0704bd77f5c1de9afebbaf387af0cbdc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.DependencyInjection; | |
using PasswordGenerator; | |
using Quartz; | |
using Cornerstone.Model.iwise; | |
using Cornerstone.Model.Cornerstone.Actions.LDAP; | |
using Cornerstone.Services; | |
using System; | |
using System.Collections.Generic; | |
using System.DirectoryServices; | |
using System.DirectoryServices.AccountManagement; | |
using System.Linq; | |
using System.Text; | |
using System.Text.RegularExpressions; | |
using System.Threading.Tasks; | |
using Cornerstone.Model.Cornerstone.Actions; | |
using Cornerstone.Model.Cornerstone; | |
namespace Cornerstone.Jobs | |
{ | |
internal class ContactMonitoringJob : IJob | |
{ | |
private readonly ContactService contactService; | |
private readonly LdapService ldapService; | |
private readonly ActionService actionService; | |
private readonly IwzCommonService iwzCommonService; | |
private readonly SettingsService settingsService; | |
public ContactMonitoringJob(ContactService contactService, LdapService ldapService, ActionService actionService, IwzCommonService iwzCommonService, SettingsService settingsService) | |
{ | |
this.contactService = contactService; | |
this.ldapService = ldapService; | |
this.actionService = actionService; | |
this.iwzCommonService = iwzCommonService; | |
this.settingsService = settingsService; | |
} | |
private static ContactKeyMapping GetKeyMappingForContact(ICollection<ContactKeyMapping> keyMappings, WmContact iwzContact) | |
{ | |
return keyMappings.SingleOrDefault(m => m.DefaultSamAccountName == iwzContact.GetSamAccountName() && m.FirstName == iwzContact.FirstName && m.Surname == iwzContact.Surname); | |
} | |
private (bool foundPartialMatch, UserPrincipal matchingDomainAccount) SearchForMatchInDomain(WmContact iwzContact, string contactSam, List<UserPrincipal> domainAccounts) | |
{ | |
int domainUsersIndex = 0; | |
bool samsMatch = false; | |
bool fullNamesMatch = false; | |
UserPrincipal matchingDomainAccount = null; | |
while (domainUsersIndex < domainAccounts.Count && !samsMatch) | |
{ | |
var domainAccount = domainAccounts[domainUsersIndex++]; | |
samsMatch = string.Compare(contactSam, domainAccount.SamAccountName, true) == 0; | |
if (samsMatch) | |
{ | |
fullNamesMatch = | |
string.Compare(iwzContact.FirstName, domainAccount.GivenName, true) == 0 | |
&& string.Compare(iwzContact.Surname, domainAccount.Surname, true) == 0; | |
if (fullNamesMatch) | |
{ | |
matchingDomainAccount = domainAccount; | |
} | |
} | |
} | |
bool partialMatch = samsMatch && !fullNamesMatch; | |
return (partialMatch, matchingDomainAccount); | |
} | |
private (string contactOU, List<string> contactGroups) DetermineOuAndGroupsForContact(WmContact iwzContact, ApplicationSettings settings) | |
{ | |
string contactOU = null; | |
List<string> contactGroups = new(); | |
if (iwzContact.IsStudent) | |
{ | |
int campusId = int.Parse(iwzContact.Campus); | |
if (iwzContact.SchoolYear.HasValue) | |
{ | |
if (settings.PrimarySchoolYears.Contains(iwzContact.SchoolYear.Value)) | |
{ | |
contactOU = settings.PrimaryStudentOusByCampus?.GetValueOrDefault(campusId); | |
contactGroups.Add(settings.PrimaryStudentGroupsByCampus?.GetValueOrDefault(campusId)); | |
} | |
else if (settings.SecondarySchoolYears.Contains(iwzContact.SchoolYear.Value)) | |
{ | |
contactOU = settings.SecondaryStudentOusByCampus?.GetValueOrDefault(campusId); | |
contactGroups.Add(settings.SecondaryStudentGroupsByCampus?.GetValueOrDefault(campusId)); | |
} | |
} | |
} | |
else | |
{ | |
var facultyNames = iwzContact.Faculties.ToList(); | |
if (facultyNames.Count == 0) | |
{ | |
contactOU = null; | |
} | |
else | |
{ | |
var facultyMappings = iwzCommonService.GetFacultyMappings(facultyNames); | |
contactOU = facultyMappings.FirstOrDefault()?.OU; | |
contactGroups.AddRange(facultyMappings.SelectMany(m => m.AdGroups).Distinct()); | |
} | |
} | |
return (contactOU, contactGroups); | |
} | |
private static bool CheckIfContactMissingKeyData(WmContact iwzContact, string contactSam) | |
{ | |
return contactSam == null || string.IsNullOrWhiteSpace(iwzContact.FirstName) || string.IsNullOrWhiteSpace(iwzContact.Surname); | |
} | |
private void GenerateDataCheckMessagesForContact(WmContact contact, ApplicationSettings settings, StringBuilder sb) | |
{ | |
int campusId = int.Parse(contact.Campus); | |
if (contact.IsStudent) | |
{ | |
if (!contact.SchoolYear.HasValue) | |
{ | |
sb.AppendLine($"Student \"{contact.GetSamAccountName()}\" without School Year"); | |
} | |
else | |
{ | |
string ou = null, group = null; | |
string studentLevel = ""; | |
bool isPrimaryStudent = settings.PrimarySchoolYears.Contains(contact.SchoolYear.Value); | |
bool isSecondaryStudent = settings.SecondarySchoolYears.Contains(contact.SchoolYear.Value); | |
if (!isPrimaryStudent && !isSecondaryStudent) | |
{ | |
sb.AppendLine($"School Year ({contact.SchoolYear.Value})[{contact.SchoolYearDesc}] assigned to student \"{contact.GetSamAccountName()}\" is not classified as Primary nor Secondary."); | |
} | |
else | |
{ | |
if (isPrimaryStudent) | |
{ | |
studentLevel = "Primary"; | |
ou = settings.PrimaryStudentOusByCampus?.GetValueOrDefault(campusId); | |
group = settings.PrimaryStudentGroupsByCampus?.GetValueOrDefault(campusId); | |
} | |
else if (isSecondaryStudent) | |
{ | |
studentLevel = "Secondary"; | |
ou = settings.SecondaryStudentOusByCampus?.GetValueOrDefault(campusId); | |
group = settings.SecondaryStudentGroupsByCampus?.GetValueOrDefault(campusId); | |
} | |
if (string.IsNullOrWhiteSpace(ou)) | |
{ | |
sb.AppendLine($"Missing configuration \"{studentLevel} Student OU\" for campus of ID \"{campusId}\"."); | |
} | |
if (string.IsNullOrWhiteSpace(group)) | |
{ | |
sb.AppendLine($"Missing configuration \"{studentLevel} Student Group\" for campus of ID \"{campusId}\"."); | |
} | |
} | |
} | |
} | |
if (contact.IsStudent && string.IsNullOrWhiteSpace(contact.ForeignKey)) | |
{ | |
sb.AppendLine("Missing ForeignKey in contact record."); | |
} | |
if (string.IsNullOrWhiteSpace(contact.FirstName)) | |
{ | |
sb.AppendLine("Missing FirstName in contact record."); | |
} | |
if (string.IsNullOrWhiteSpace(contact.Surname)) | |
{ | |
sb.AppendLine("Missing Surname in contact record."); | |
} | |
if (!contact.IsStudent) | |
{ | |
if (contact.Faculties.Count == 0) | |
{ | |
sb.AppendLine("Contact is not a memeber of any faculty."); | |
} | |
else | |
{ | |
var facultyNames = contact.Faculties.ToList(); | |
var facultyMapping = iwzCommonService.GetFacultyMappings(facultyNames).FirstOrDefault(); | |
if (facultyMapping == null) | |
{ | |
sb.AppendLine($"Could not find a mapping for any of the following faculties: [{facultyNames.Aggregate((a, b) => $"{a}, {b}")}]"); | |
} | |
} | |
} | |
} | |
private string GetUniqueCnForContact(WmContact contact, List<UserPrincipal> domainUsers) | |
{ | |
string contactCN = $"{contact.FirstName} {contact.Surname}"; | |
List<string> cnMatches = | |
domainUsers | |
.Where(du => | |
{ | |
var de = du.GetUnderlyingObject() as DirectoryEntry; | |
string duCn = de.Properties["cn"].Value.ToString(); | |
return duCn.StartsWith(contactCN); | |
}) | |
.Select(du => | |
{ | |
var de = du.GetUnderlyingObject() as DirectoryEntry; | |
return de.Properties["cn"].Value.ToString(); | |
}) | |
.ToList(); | |
for (int i = 2; i < 10 && cnMatches.Contains(contactCN); i++) | |
{ | |
contactCN = $"{contactCN} {i}"; | |
} | |
return contactCN; | |
} | |
public async Task Execute(IJobExecutionContext context) | |
{ | |
Console.WriteLine("Executing ContactMonitoringJob"); | |
var iwzCurrentContacts = contactService.GetAllCurrentContacts(); | |
Console.WriteLine($"Found {iwzCurrentContacts.Count} contacts in IWZ."); | |
List<CornerstoneAction> actions = new(); | |
StringBuilder sbNotes = new(); | |
var settings = settingsService.GetSettings(); | |
var keyMappings = settingsService.GetContactKeyMappings(); | |
var domainUsersIncludingDisabled = ldapService.GetDomainAccounts(true); | |
foreach (var iwzContact in iwzCurrentContacts) | |
{ | |
var keyMapping = GetKeyMappingForContact(keyMappings, iwzContact); | |
var contactSam = keyMapping?.SamAccountName ?? iwzContact.GetSamAccountName(); | |
if (!CheckIfContactMissingKeyData(iwzContact, contactSam)) | |
{ | |
if (iwzContact.IsCurrentStudent || iwzContact.IsCurrentStaff) // not a student relative | |
{ | |
var (foundPartialMatch, matchingDomainAccount) = | |
SearchForMatchInDomain(iwzContact, contactSam, domainUsersIncludingDisabled); | |
if (foundPartialMatch) // do not continue processing this contact in case of partial match | |
{ | |
if (keyMapping == null) | |
{ | |
settingsService.CreateKeyMappingForContact(iwzContact.FirstName, iwzContact.Surname, contactSam, iwzContact.IsStaff); | |
} | |
} | |
else | |
{ | |
if (matchingDomainAccount == null || matchingDomainAccount.IsDisabled()) | |
{ | |
sbNotes.Clear(); | |
GenerateDataCheckMessagesForContact(iwzContact, settings, sbNotes); | |
string contactEmail = $"{contactSam}@{(iwzContact.IsStudent ? settings.StudentDomain : settings.StaffDomain)}"; | |
var (contactOU, contactGroups) = DetermineOuAndGroupsForContact(iwzContact, settings); | |
if (matchingDomainAccount != null) //disabled user | |
{ | |
string contactCN = matchingDomainAccount.DisplayName; | |
actions.Add(new EnableUserAction(iwzContact, contactSam, contactCN, contactOU, contactGroups, contactEmail, sbNotes.ToString())); | |
} | |
else | |
{ | |
string contactCN = GetUniqueCnForContact(iwzContact, domainUsersIncludingDisabled); | |
var password = new Password().IncludeLowercase().IncludeNumeric().IncludeUppercase(); | |
actions.Add(new AddUserAction(iwzContact, contactSam, contactCN, contactOU, contactGroups, contactEmail, password.Next(), sbNotes.ToString())); | |
} | |
} | |
} | |
} | |
} | |
} | |
if (actions.Count > 0) | |
{ | |
var filteredActions = actionService.FilterOutExistingActions(actions); | |
actionService.AddUserActions(filteredActions); | |
} | |
Console.WriteLine($"{actions.Count} actions"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment