2da2b257a5
UIExtension content renders at the bottom of _Layout.cshtml by design. Added wrapper div with ID and jQuery script to move the panel after #User_Show_AssignedDevices on the user page, falling back to after #User_Show_Subjects if the assignment section isn't present.
146 lines
5.9 KiB
C#
146 lines
5.9 KiB
C#
using Disco.Data.Repository;
|
|
using Disco.Models.UI.User;
|
|
using Disco.Services.Interop.ActiveDirectory;
|
|
using Disco.Services.Plugins;
|
|
using Disco.Services.Plugins.Features.UIExtension;
|
|
using System;
|
|
using System.Text;
|
|
using System.Web.Mvc;
|
|
|
|
namespace Disco.Plugins.ADCompare.Features
|
|
{
|
|
[PluginFeature(Id = "ADCompareUserUI", Name = "User Page - AD Compare")]
|
|
public class UserUIExtension : UIExtensionFeature<UserShowModel>
|
|
{
|
|
public override void Initialize(DiscoDataContext Database)
|
|
{
|
|
Register();
|
|
}
|
|
|
|
public override UIExtensionResult ExecuteAction(ControllerContext context, UserShowModel model)
|
|
{
|
|
var user = model.User;
|
|
if (user == null || string.IsNullOrEmpty(user.UserId))
|
|
return Nothing();
|
|
|
|
var html = new StringBuilder();
|
|
|
|
// Wrapper div with unique ID for relocation
|
|
html.Append("<div id='adcompare-user-panel'>");
|
|
html.Append("<div class='form-group' style='margin-top:15px;'>");
|
|
html.Append("<h4 style='border-bottom:1px solid #ddd;padding-bottom:5px;'>");
|
|
html.Append("<i class='fa fa-exchange'></i> AD Details</h4>");
|
|
|
|
try
|
|
{
|
|
var adUser = ActiveDirectory.RetrieveADUserAccount(
|
|
user.UserId,
|
|
new[] { "lastLogonTimestamp", "whenCreated", "memberOf" });
|
|
|
|
if (adUser == null)
|
|
{
|
|
html.Append("<div class='alert alert-danger'>");
|
|
html.Append("<i class='fa fa-times-circle'></i> User not found in Active Directory");
|
|
html.Append("</div>");
|
|
}
|
|
else
|
|
{
|
|
html.Append("<table class='table table-condensed' style='margin-bottom:10px;'>");
|
|
|
|
html.Append("<tr><td style='width:180px;'><strong>AD Status</strong></td><td>");
|
|
if (adUser.IsDisabled)
|
|
{
|
|
html.Append("<span class='text-danger'><i class='fa fa-ban'></i> Disabled</span>");
|
|
}
|
|
else
|
|
{
|
|
html.Append("<span class='text-success'><i class='fa fa-check-circle'></i> Active</span>");
|
|
}
|
|
html.Append("</td></tr>");
|
|
|
|
var lastLogonTicks = adUser.GetPropertyValue<long>("lastLogonTimestamp");
|
|
html.Append("<tr><td><strong>Last Login</strong></td><td>");
|
|
if (lastLogonTicks > 0)
|
|
{
|
|
try
|
|
{
|
|
var lastLogon = DateTime.FromFileTime(lastLogonTicks);
|
|
var ago = DateTime.Now.Subtract(lastLogon);
|
|
html.Append(Encode(lastLogon.ToString("dd/MM/yyyy hh:mm tt")));
|
|
html.Append(" <span class='text-muted'>(");
|
|
html.Append(FormatTimeAgo(ago));
|
|
html.Append(")</span>");
|
|
|
|
if (ago.TotalDays > 30 && !adUser.IsDisabled)
|
|
{
|
|
html.Append(" <span class='label label-warning'>Inactive 30+ days</span>");
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
html.Append("<em class='text-muted'>Unable to parse</em>");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
html.Append("<em class='text-muted'>Never</em>");
|
|
}
|
|
html.Append("</td></tr>");
|
|
|
|
if (!string.IsNullOrEmpty(adUser.DistinguishedName))
|
|
{
|
|
html.Append("<tr><td><strong>AD Location</strong></td><td>");
|
|
html.Append("<small>");
|
|
html.Append(Encode(adUser.DistinguishedName));
|
|
html.Append("</small>");
|
|
html.Append("</td></tr>");
|
|
}
|
|
|
|
html.Append("</table>");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
html.Append("<div class='alert alert-warning'>");
|
|
html.Append("<i class='fa fa-exclamation-triangle'></i> AD lookup error: ");
|
|
html.Append(Encode(ex.Message));
|
|
html.Append("</div>");
|
|
}
|
|
|
|
html.Append("</div>"); // form-group
|
|
html.Append("</div>"); // wrapper
|
|
|
|
// Script to relocate panel under the device assignment section
|
|
html.Append("<script type='text/javascript'>");
|
|
html.Append("$(function(){");
|
|
html.Append("var p=$('#adcompare-user-panel');");
|
|
html.Append("var t=$('#User_Show_AssignedDevices');");
|
|
html.Append("if(t.length){p.insertAfter(t);}");
|
|
html.Append("else{var s=$('#User_Show_Subjects');if(s.length){p.insertAfter(s);}}");
|
|
html.Append("});");
|
|
html.Append("</script>");
|
|
|
|
return Literal(html.ToString());
|
|
}
|
|
|
|
private string Encode(string value)
|
|
{
|
|
if (string.IsNullOrEmpty(value)) return "";
|
|
return System.Web.HttpUtility.HtmlEncode(value);
|
|
}
|
|
|
|
private string FormatTimeAgo(TimeSpan span)
|
|
{
|
|
if (span.TotalDays >= 365)
|
|
return string.Format("{0} year(s) ago", (int)(span.TotalDays / 365));
|
|
if (span.TotalDays >= 30)
|
|
return string.Format("{0} month(s) ago", (int)(span.TotalDays / 30));
|
|
if (span.TotalDays >= 1)
|
|
return string.Format("{0} day(s) ago", (int)span.TotalDays);
|
|
if (span.TotalHours >= 1)
|
|
return string.Format("{0} hour(s) ago", (int)span.TotalHours);
|
|
return "Just now";
|
|
}
|
|
}
|
|
}
|