diff --git a/Features/ADCompareService.cs b/Features/ADCompareService.cs new file mode 100644 index 0000000..e86804a --- /dev/null +++ b/Features/ADCompareService.cs @@ -0,0 +1,119 @@ +using Disco.Data.Repository; +using Disco.Models.Repository; +using Disco.Plugins.ADCompare.Models; +using Disco.Services.Interop.ActiveDirectory; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Disco.Plugins.ADCompare.Features +{ + public class ADCompareService + { + private readonly DiscoDataContext database; + + public ADCompareService(DiscoDataContext database) + { + this.database = database; + } + + /// + /// Compare all Disco users against their Active Directory accounts. + /// Returns a summary with per-user comparison results. + /// + public ComparisonSummary CompareAllUsers() + { + var summary = new ComparisonSummary(); + + // Load all users from Disco database + var discoUsers = database.Users.ToList(); + summary.TotalDiscoUsers = discoUsers.Count; + + foreach (var discoUser in discoUsers) + { + var result = CompareUser(discoUser); + summary.Results.Add(result); + } + + summary.UsersCompared = summary.Results.Count(r => r.UserFoundInAD); + summary.UsersNotFoundInAD = summary.Results.Count(r => !r.UserFoundInAD); + summary.UsersWithMismatches = summary.Results.Count(r => r.HasMismatches); + summary.UsersInSync = summary.Results.Count(r => r.UserFoundInAD && !r.HasMismatches && !r.ADAccountDisabled); + summary.ADAccountsDisabled = summary.Results.Count(r => r.ADAccountDisabled); + + return summary; + } + + /// + /// Compare a single Disco user against their AD account. + /// + public UserComparisonResult CompareUser(User discoUser) + { + var result = new UserComparisonResult + { + UserId = discoUser.UserId, + DisplayName = discoUser.DisplayName + }; + + try + { + // Look up the user in AD using their UserId (DOMAIN\username format) + var adUser = ActiveDirectory.RetrieveADUserAccount(discoUser.UserId); + + if (adUser == null) + { + result.UserFoundInAD = false; + return result; + } + + result.UserFoundInAD = true; + result.ADAccountDisabled = adUser.IsDisabled; + + // Compare core fields + CompareField(result, "Display Name", discoUser.DisplayName, adUser.DisplayName); + CompareField(result, "Surname", discoUser.Surname, adUser.Surname); + CompareField(result, "Given Name", discoUser.GivenName, adUser.GivenName); + CompareField(result, "Email Address", discoUser.EmailAddress, adUser.Email); + CompareField(result, "Phone Number", discoUser.PhoneNumber, adUser.Phone); + } + catch (Exception ex) + { + // If we can't look up the user in AD, mark as not found + result.UserFoundInAD = false; + result.Mismatches.Add(new FieldMismatch( + "AD Lookup Error", + discoUser.UserId, + ex.Message + )); + } + + return result; + } + + /// + /// Compare a single field between Disco and AD values. + /// Treats null and empty string as equivalent. + /// + private void CompareField(UserComparisonResult result, string fieldName, string discoValue, string adValue) + { + var normalisedDisco = NormaliseValue(discoValue); + var normalisedAD = NormaliseValue(adValue); + + if (!string.Equals(normalisedDisco, normalisedAD, StringComparison.OrdinalIgnoreCase)) + { + result.Mismatches.Add(new FieldMismatch(fieldName, discoValue ?? "(empty)", adValue ?? "(empty)")); + } + } + + /// + /// Normalise a value for comparison - treat null and whitespace as empty. + /// + private string NormaliseValue(string value) + { + if (string.IsNullOrWhiteSpace(value)) + return string.Empty; + + return value.Trim(); + } + } +}