Add DetailsProvider feature for AD comparison and photo sync
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Services.Interop.ActiveDirectory;
|
||||
using Disco.Services.Plugins;
|
||||
using Disco.Services.Plugins.Features.DetailsProvider;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Disco.Plugins.ADCompare.Features
|
||||
{
|
||||
[PluginFeature(Id = "ADCompareDetails", Name = "AD Compare Detail Provider", PrimaryFeature = true)]
|
||||
public class ADCompareDetailsProvider : DetailsProviderFeature
|
||||
{
|
||||
private const string DetailsScope = "Details";
|
||||
private const string ADCompareScope = "ADCompare";
|
||||
|
||||
/// <summary>
|
||||
/// Updates all user details by comparing AD attributes against Disco records.
|
||||
/// Stores comparison metadata as UserDetails with ADCompare scope.
|
||||
/// </summary>
|
||||
public override void UpdateAllDetails(DiscoDataContext database)
|
||||
{
|
||||
var users = database.Users.ToList();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
try
|
||||
{
|
||||
var adUser = ActiveDirectory.RetrieveADUserAccount(user.UserId);
|
||||
if (adUser == null)
|
||||
{
|
||||
SetUserDetail(database, user, ADCompareScope, "ADStatus", "NotFound");
|
||||
SetUserDetail(database, user, ADCompareScope, "LastChecked", DateTime.Now.ToString("o"));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Store comparison results as UserDetails
|
||||
SetUserDetail(database, user, ADCompareScope, "ADStatus", adUser.IsDisabled ? "Disabled" : "Active");
|
||||
SetUserDetail(database, user, ADCompareScope, "LastChecked", DateTime.Now.ToString("o"));
|
||||
|
||||
// Store AD values for reference
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_DisplayName", adUser.DisplayName ?? string.Empty);
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_Surname", adUser.Surname ?? string.Empty);
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_GivenName", adUser.GivenName ?? string.Empty);
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_Email", adUser.Email ?? string.Empty);
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_Phone", adUser.Phone ?? string.Empty);
|
||||
SetUserDetail(database, user, ADCompareScope, "AD_DistinguishedName", adUser.DistinguishedName ?? string.Empty);
|
||||
|
||||
// Check for mismatches
|
||||
var mismatches = new List<string>();
|
||||
if (!StringMatch(user.DisplayName, adUser.DisplayName)) mismatches.Add("DisplayName");
|
||||
if (!StringMatch(user.Surname, adUser.Surname)) mismatches.Add("Surname");
|
||||
if (!StringMatch(user.GivenName, adUser.GivenName)) mismatches.Add("GivenName");
|
||||
if (!StringMatch(user.EmailAddress, adUser.Email)) mismatches.Add("Email");
|
||||
if (!StringMatch(user.PhoneNumber, adUser.Phone)) mismatches.Add("Phone");
|
||||
|
||||
SetUserDetail(database, user, ADCompareScope, "MismatchedFields",
|
||||
mismatches.Count > 0 ? string.Join(",", mismatches) : "None");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
SetUserDetail(database, user, ADCompareScope, "ADStatus", "Error");
|
||||
SetUserDetail(database, user, ADCompareScope, "ADError", ex.Message);
|
||||
SetUserDetail(database, user, ADCompareScope, "LastChecked", DateTime.Now.ToString("o"));
|
||||
}
|
||||
}
|
||||
|
||||
database.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets user photo from AD (thumbnailPhoto attribute).
|
||||
/// Returns null if no photo or cache is still valid.
|
||||
/// </summary>
|
||||
public override byte[] GetUserPhoto(DiscoDataContext database, User user, DateTime? cacheTimestamp)
|
||||
{
|
||||
// Only refresh photos older than 24 hours
|
||||
if (cacheTimestamp.HasValue && cacheTimestamp.Value > DateTime.Now.AddHours(-24))
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
var adUser = ActiveDirectory.RetrieveADUserAccount(user.UserId, new[] { "thumbnailPhoto" });
|
||||
if (adUser == null)
|
||||
return null;
|
||||
|
||||
var photoData = adUser.GetPropertyValue<byte[]>("thumbnailPhoto");
|
||||
return photoData;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private bool StringMatch(string discoValue, string adValue)
|
||||
{
|
||||
var a = string.IsNullOrWhiteSpace(discoValue) ? string.Empty : discoValue.Trim();
|
||||
var b = string.IsNullOrWhiteSpace(adValue) ? string.Empty : adValue.Trim();
|
||||
return string.Equals(a, b, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void SetUserDetail(DiscoDataContext database, User user, string scope, string key, string value)
|
||||
{
|
||||
var existing = database.UserDetails
|
||||
.FirstOrDefault(d => d.UserId == user.UserId && d.Scope == scope && d.Key == key);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
database.UserDetails.Add(new UserDetail
|
||||
{
|
||||
UserId = user.UserId,
|
||||
Scope = scope,
|
||||
Key = key,
|
||||
Value = value
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user