Initial commit: JDE Scoping Tool migration project
Set up repository with legacy .NET Framework 4.8 source (OLD/), new .NET 10 Blazor solution (NEW/), OpenSpec specifications, documentation, and project configuration.
This commit is contained in:
+100
@@ -0,0 +1,100 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using OfficeOpenXml;
|
||||
using OfficeOpenXml.Style;
|
||||
|
||||
namespace WebInterface.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Lot # / work order # template generator
|
||||
/// </summary>
|
||||
public class ExcelTemplateGenerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates Excel spreadsheet data entry template
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Data type of source data</typeparam>
|
||||
/// <param name="sourceData">Source data to display in template</param>
|
||||
/// <param name="headerText">Column header text</param>
|
||||
/// <returns>Generated spreadsheet</returns>
|
||||
public static byte[] Generate<T>(List<T> sourceData, string headerText)
|
||||
{
|
||||
//Create worksheet to hold data
|
||||
ExcelPackage package = new ExcelPackage();
|
||||
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Data Entry Template");
|
||||
|
||||
//Write header
|
||||
worksheet.Cells[1, 1].Value = headerText;
|
||||
worksheet.Cells[1, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||||
worksheet.Cells[1, 1].Style.Font.Bold = true;
|
||||
worksheet.Cells[1, 1].Style.Fill.PatternType = ExcelFillStyle.Solid;
|
||||
worksheet.Cells[1, 1].Style.Fill.BackgroundColor.SetColor(Color.Gainsboro);
|
||||
worksheet.Column(1).Width = 45;
|
||||
|
||||
//Write uploaded data
|
||||
if (sourceData != null)
|
||||
{
|
||||
int row = 2;
|
||||
foreach (T element in sourceData)
|
||||
{
|
||||
worksheet.Cells[row++, 1].Value = element;
|
||||
}
|
||||
}
|
||||
|
||||
//Write result
|
||||
MemoryStream fileStream = new MemoryStream();
|
||||
package.SaveAs(fileStream);
|
||||
fileStream.Position = 0;
|
||||
byte[] data = fileStream.ToArray();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates Excel spreadsheet data entry template
|
||||
/// </summary>
|
||||
/// <param name="sourceData">Source data to display in template</param>
|
||||
/// <param name="headerText">Column header text</param>
|
||||
/// <returns>Generated spreadsheet</returns>
|
||||
public static byte[] Generate(object[][] sourceData, string[] headerText)
|
||||
{
|
||||
//Create worksheet to hold data
|
||||
ExcelPackage package = new ExcelPackage();
|
||||
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Data Entry Template");
|
||||
|
||||
int numColumns = headerText.Length;
|
||||
|
||||
//Write header
|
||||
ExcelRange header = worksheet.Cells[1, 1, 1, numColumns];
|
||||
header.LoadFromArrays(new List<object[]> { headerText });
|
||||
|
||||
header.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
|
||||
header.Style.Font.Bold = true;
|
||||
header.Style.Fill.PatternType = ExcelFillStyle.Solid;
|
||||
header.Style.Fill.BackgroundColor.SetColor(Color.Gainsboro);
|
||||
|
||||
//Write uploaded data
|
||||
if (sourceData != null && sourceData.Length > 0)
|
||||
{
|
||||
ExcelRange dataRange = worksheet.Cells[2, 1, sourceData.Length + 2, numColumns];
|
||||
dataRange.LoadFromArrays(sourceData);
|
||||
}
|
||||
|
||||
//Size columns
|
||||
for (int col = 1; col <= numColumns; col++)
|
||||
{
|
||||
worksheet.Column(col).Width = 65;
|
||||
worksheet.Column(col).Style.Numberformat.Format = "@";
|
||||
}
|
||||
|
||||
//Write result
|
||||
MemoryStream fileStream = new MemoryStream();
|
||||
package.SaveAs(fileStream);
|
||||
fileStream.Position = 0;
|
||||
byte[] data = fileStream.ToArray();
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+65
@@ -0,0 +1,65 @@
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using DataModel.Models;
|
||||
using WebInterface.Security;
|
||||
|
||||
namespace WebInterface.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// HTML helper methods
|
||||
/// </summary>
|
||||
public static class HtmlHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets current user for request
|
||||
/// </summary>
|
||||
/// <param name="html">HTML helper context</param>
|
||||
/// <returns>LDAP entry for current session</returns>
|
||||
public static LDAPEntry CurrentUser(this HtmlHelper html)
|
||||
{
|
||||
//Verify user is authenticated before continuing
|
||||
if (!html.ViewContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
LDAPEntry currentUser = null;
|
||||
try
|
||||
{
|
||||
UserIdentity identity = new UserIdentity(html.ViewContext.RequestContext.HttpContext.User.Identity as ClaimsIdentity);
|
||||
currentUser = identity.ToLDAPEntry();
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Do nothing
|
||||
}
|
||||
|
||||
return currentUser;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates logon control for user/session
|
||||
/// </summary>
|
||||
/// <param name="html">HTML helper context</param>
|
||||
/// <returns>Raw HTML output for logon control</returns>
|
||||
public static MvcHtmlString LogonControl(this HtmlHelper html)
|
||||
{
|
||||
LDAPEntry currentUser = html.CurrentUser();
|
||||
|
||||
UrlHelper urlHelper = new UrlHelper(html.ViewContext.RequestContext);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
if (currentUser == null || html.ViewContext.RequestContext.HttpContext.User.Identity==null|| !html.ViewContext.RequestContext.HttpContext.User.Identity.IsAuthenticated)
|
||||
{
|
||||
builder.AppendFormat("<a href='{0}' class='btn btn-primary'>Login</a>", urlHelper.Action("Login", "Account", null, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendFormat("<span style='color: #9d9d9d;'>{0}</span> <a href='{1}' class='btn btn-primary'>Logout</a>", currentUser.DisplayName, urlHelper.Action("Logout", "Account", null, null));
|
||||
}
|
||||
|
||||
return new MvcHtmlString(builder.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+66
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace WebInterface.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom JSON action result using JSON.NET library
|
||||
/// </summary>
|
||||
public class JsonNetResult : JsonResult
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialization settings
|
||||
/// </summary>
|
||||
public JsonSerializerSettings Settings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
public JsonNetResult()
|
||||
{
|
||||
Settings = new JsonSerializerSettings
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Error
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates the resulting JSON output
|
||||
/// </summary>
|
||||
/// <param name="context">Controller context for outputting</param>
|
||||
public override void ExecuteResult(ControllerContext context)
|
||||
{
|
||||
//Verify context is valid before continuing
|
||||
if (context == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
//Verify HTTP method is valid before continuing
|
||||
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
throw new InvalidOperationException("JSON GET is not allowed");
|
||||
}
|
||||
|
||||
//Write response
|
||||
HttpResponseBase response = context.HttpContext.Response;
|
||||
response.ContentType = string.IsNullOrEmpty(ContentType) ? "application/json" : ContentType;
|
||||
|
||||
if (ContentEncoding != null)
|
||||
response.ContentEncoding = ContentEncoding;
|
||||
if (Data == null)
|
||||
return;
|
||||
|
||||
var scriptSerializer = JsonSerializer.Create(Settings);
|
||||
|
||||
using (var sw = new StringWriter())
|
||||
{
|
||||
scriptSerializer.Serialize(sw, Data);
|
||||
response.Write(sw.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+162
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using System.DirectoryServices;
|
||||
using System.Linq;
|
||||
using DataModel.Models;
|
||||
using NLog;
|
||||
using SearchResult = System.DirectoryServices.SearchResult;
|
||||
|
||||
namespace WebInterface.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// LDAP server interface helper methods
|
||||
/// </summary>
|
||||
public class LDAPHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// LDAP user lookup format
|
||||
/// </summary>
|
||||
private const string LDAP_LOOKUP_FORMAT = "(sAMAccountName={0})";
|
||||
|
||||
/// <summary>
|
||||
/// Shared logger instance
|
||||
/// </summary>
|
||||
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
||||
|
||||
/// <summary>
|
||||
/// Authenticates the user's credentials against the given LDAP server
|
||||
/// </summary>
|
||||
/// <param name="username">LDAP username</param>
|
||||
/// <param name="password">LDAP password</param>
|
||||
/// <param name="serverURL">LDAP server URL</param>
|
||||
/// <param name="ldapGroup">LDAP group to filter for</param>
|
||||
/// <returns>Whether or not user's credentials are valid</returns>
|
||||
public static bool Authenticate(string username, string password, string serverURL, string ldapGroup = null)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
try
|
||||
{
|
||||
//Form full LDAP URL
|
||||
string ldapURL = $"LDAP://{serverURL}";
|
||||
|
||||
//Attempt to find entry
|
||||
DirectoryEntry entry = new DirectoryEntry(ldapURL, username, password);
|
||||
object val = entry.NativeObject;
|
||||
|
||||
result = true;
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
//Log but do not forward error
|
||||
logger.Error("Authenticate: failed to authenticate user '{0}' against LDAP server '{1}': {2}.", username, serverURL, error.Message);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if user is in given group
|
||||
/// </summary>
|
||||
/// <param name="username">LDAP username</param>
|
||||
/// <param name="password">LDAP password</param>
|
||||
/// <param name="serverURL">LDAP server URL</param>
|
||||
/// <param name="ldapGroup">LDAP group to filter for</param>
|
||||
/// <param name="ldapFilter">LDAP search filter</param>
|
||||
/// <returns>Whether or not user belongs to given group</returns>
|
||||
public static bool IsInGroup(string username, string password, string serverURL, string ldapGroup, string ldapFilter = LDAP_LOOKUP_FORMAT)
|
||||
{
|
||||
try
|
||||
{
|
||||
//Form full LDAP URL
|
||||
string ldapURL = $"LDAP://{serverURL}";
|
||||
|
||||
//Create a LDAP searcher
|
||||
DirectorySearcher searcher = new DirectorySearcher
|
||||
{
|
||||
SearchRoot = new DirectoryEntry(ldapURL, username, password),
|
||||
Filter = string.Format(ldapFilter, username)
|
||||
};
|
||||
|
||||
foreach (SearchResult searchResult in searcher.FindAll())
|
||||
{
|
||||
DirectoryEntry directoryEntry = searchResult.GetDirectoryEntry();
|
||||
foreach (var groupName in directoryEntry.Properties["memberOf"])
|
||||
{
|
||||
if (string.Equals(groupName.ToString(), ldapGroup, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception error)
|
||||
{
|
||||
//Log but do not forward error
|
||||
logger.Error("Authenticate: failed to authenticate user '{0}' against LDAP server '{1}': {2}.", username, serverURL, error.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches LDAP server for matching entry
|
||||
/// </summary>
|
||||
/// <param name="serverURL">URL for LDAP server to search</param>
|
||||
/// <param name="username">LDAP server binding username</param>
|
||||
/// <param name="password">LDAP server binding password</param>
|
||||
/// <param name="ldapFilter">LDAP search filter</param>
|
||||
/// <returns>Collection of matching LDAP entries</returns>
|
||||
public static LDAPEntry LookupUser(string username, string password, string serverURL, string ldapFilter = LDAP_LOOKUP_FORMAT)
|
||||
{
|
||||
LDAPEntry result = null;
|
||||
|
||||
//Form full LDAP URL
|
||||
string ldapURL = $"LDAP://{serverURL}";
|
||||
|
||||
//Create a LDAP searcher
|
||||
DirectorySearcher searcher = new DirectorySearcher
|
||||
{
|
||||
SearchRoot = new DirectoryEntry(ldapURL, username, password),
|
||||
Filter = string.Format(ldapFilter, username)
|
||||
};
|
||||
|
||||
//Loop through search results
|
||||
foreach (SearchResult searchResult in searcher.FindAll())
|
||||
{
|
||||
//Parse the entry's details
|
||||
result = new LDAPEntry()
|
||||
{
|
||||
DN = ExtractProperty(searchResult, "distinguishedName"),
|
||||
Username = username.ToLower(),
|
||||
FirstName = ExtractProperty(searchResult, "givenName"),
|
||||
LastName = ExtractProperty(searchResult, "sn"),
|
||||
EmailAddress = ExtractProperty(searchResult, "mail"),
|
||||
Title = ExtractProperty(searchResult, "title")
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(result.FirstName) && !string.IsNullOrEmpty(result.DisplayName))
|
||||
{
|
||||
result.FirstName = result.DisplayName;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result.LastName) && !string.IsNullOrEmpty(result.DisplayName))
|
||||
{
|
||||
result.LastName = result.DisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the specified property from the LDAP search result
|
||||
/// </summary>
|
||||
/// <param name="result">LDAP search result to parse property from</param>
|
||||
/// <param name="key">Lookup key for property</param>
|
||||
/// <returns>Property value if it exists, empty string if it does not exist</returns>
|
||||
private static string ExtractProperty(SearchResult result, string key)
|
||||
{
|
||||
return result.Properties[key].Count > 0 ? (string)result.Properties[key][0] : string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user