Dynamic Portal menu

This commit is contained in:
Andy Howard
2025-01-13 14:52:09 +00:00
parent 4a72043f00
commit ee988b1f76
21 changed files with 218 additions and 229 deletions
-13
View File
@@ -99,7 +99,6 @@ namespace Sarand.BusinessMgr.Net.Core.Web.App
} }
public DatabaseConfig ControlDatabase { get; private set; } public DatabaseConfig ControlDatabase { get; private set; }
public DatabaseConfig TemplateDatabase { get; private set; } public DatabaseConfig TemplateDatabase { get; private set; }
public List<DatabaseConfig> BusMgrDatabases { get; } = new List<DatabaseConfig>();
// Documents. // Documents.
public class DocumentsConfig public class DocumentsConfig
{ {
@@ -211,18 +210,6 @@ namespace Sarand.BusinessMgr.Net.Core.Web.App
ExtractDatabaseConfig(TemplateDatabase, templateDatabaseSection); ExtractDatabaseConfig(TemplateDatabase, templateDatabaseSection);
} }
// BusinessMgr databases.
IConfigurationSection busMgrDatabasesSection = configSection.GetSection("BusMgrDatabases");
if (busMgrDatabasesSection.Exists())
{
foreach (IConfigurationSection busMgrDbSection in busMgrDatabasesSection.GetChildren())
{
SbmAppConfig.DatabaseConfig dbConfig = new SbmAppConfig.DatabaseConfig();
ExtractDatabaseConfig(dbConfig, busMgrDbSection);
BusMgrDatabases.Add(dbConfig);
}
}
// Variants. // Variants.
foreach (ConfigurationSection variantSection in configSection.GetSection("Variants").GetChildren()) foreach (ConfigurationSection variantSection in configSection.GetSection("Variants").GetChildren())
{ {
@@ -71,8 +71,6 @@ namespace Sarand.BusinessMgr.Net.Core.Web.App
applicationParams.Add("Configuration", SbmSystem.DebugMode ? "Debug" : "Release"); applicationParams.Add("Configuration", SbmSystem.DebugMode ? "Debug" : "Release");
applicationParams.Add("Environment", EnvironmentName); applicationParams.Add("Environment", EnvironmentName);
applicationParams.Add("Control database", AppConfig.ControlDatabase.Location); applicationParams.Add("Control database", AppConfig.ControlDatabase.Location);
foreach (SbmAppConfig.DatabaseConfig dbConfig in AppConfig.BusMgrDatabases)
applicationParams.Add("BusMgr database", (dbConfig.Identifiers.Any() ? $"[{String.Join(",", dbConfig.Identifiers)}] " : "") + dbConfig.Location);
applicationParams.Add("Application root", SbmSystem.ApplicationFolder); applicationParams.Add("Application root", SbmSystem.ApplicationFolder);
if (!StringUtil.IsEmpty(AppConfig.Documents.RootFolder)) if (!StringUtil.IsEmpty(AppConfig.Documents.RootFolder))
applicationParams.Add("Documents root", AppConfig.Documents.RootFolder); applicationParams.Add("Documents root", AppConfig.Documents.RootFolder);
@@ -117,8 +117,7 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Controllers
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Model. // Model.
//------------------------------------------------------------------- protected virtual void RefreshModel(SbmModel_Base model)
protected void RefreshModel(SbmModel_Base model)
{ {
if (model == null) return; if (model == null) return;
@@ -53,7 +53,8 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.Bus
ProspectGroup, ProspectGroup,
// Associated data. // Associated data.
GroupMembers, GroupMembers,
Association_Count, AssociationOwner_Count,
AssociationTarget_Count,
// Common properties. // Common properties.
Notes, Notes,
Flag, Flag,
@@ -366,7 +366,8 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr
private static readonly String aliasAffiliate_AddPrim = "Aff_AddPrim"; private static readonly String aliasAffiliate_AddPrim = "Aff_AddPrim";
private static readonly String prefixAffiliate_AddPrim = aliasAffiliate_AddPrim + "_"; private static readonly String prefixAffiliate_AddPrim = aliasAffiliate_AddPrim + "_";
private static readonly String colNameAffiliate_GroupMembers = "GroupMembers"; private static readonly String colNameAffiliate_GroupMembers = "GroupMembers";
private static readonly String colNameAffiliate_AssociationCount = "AssocCount"; private static readonly String colNameAffiliate_AssociationOwnerCount = "AssocOwnerCount";
private static readonly String colNameAffiliate_AssociationTargetCount = "AssocTargetCount";
// Column definition population. // Column definition population.
private void SetAffiliateColDfn private void SetAffiliateColDfn
@@ -499,9 +500,13 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr
SetAffiliateColDfn(columnDfn, "Members", 90, SbmDbDfn.ColumnIdx.Unknown, ColumnAlignment.Right); SetAffiliateColDfn(columnDfn, "Members", 90, SbmDbDfn.ColumnIdx.Unknown, ColumnAlignment.Right);
columnDfn.DataName = colNameAffiliate_GroupMembers; columnDfn.DataName = colNameAffiliate_GroupMembers;
break; break;
case SbmAffiliate.Column.Association_Count: case SbmAffiliate.Column.AssociationOwner_Count:
SetAffiliateColDfn(columnDfn, "Associations", 90, SbmDbDfn.ColumnIdx.Unknown, ColumnAlignment.Right); SetAffiliateColDfn(columnDfn, "Owner Assocs", 90, SbmDbDfn.ColumnIdx.Unknown, ColumnAlignment.Right);
columnDfn.DataName = colNameAffiliate_AssociationCount; columnDfn.DataName = colNameAffiliate_AssociationOwnerCount;
break;
case SbmAffiliate.Column.AssociationTarget_Count:
SetAffiliateColDfn(columnDfn, "Target Assocs", 90, SbmDbDfn.ColumnIdx.Unknown, ColumnAlignment.Right);
columnDfn.DataName = colNameAffiliate_AssociationTargetCount;
break; break;
//----------------------------------------------------------------- //-----------------------------------------------------------------
@@ -1042,16 +1047,32 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
if (columns.HasId(SbmAffiliate.Column.Association_Count)) // Associations.
if (columns.HasId(SbmAffiliate.Column.AssociationOwner_Count))
{ {
// Count active associations. // Count active associations.
String aliasAffiliate_Associations = "AffAssocs"; String aliasAffiliate_Associations_Owner = "AffAssOwner";
DbQuery qryAssocs = new DbQuery(db.DbmsType); DbQuery qryAssocs = new DbQuery(db.DbmsType);
qryAssocs.Tables.Add((SbmDbDfn.TableIdx.Association).ToString(), aliasAffiliate_Associations); qryAssocs.Tables.Add((SbmDbDfn.TableIdx.Association).ToString(), aliasAffiliate_Associations_Owner);
qryAssocs.Columns.Add("Count(*)"); qryAssocs.Columns.Add("Count(*)");
qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdOwner, aliasAffiliate_Associations)}={SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Id, aliasAffiliate)}"); qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdOwner, aliasAffiliate_Associations_Owner)}={SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Id, aliasAffiliate)}");
qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Status, aliasAffiliate_Associations)}='{StatusCurrent}'"); qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Type, aliasAffiliate_Associations_Owner)}!={(int)Sbm.AssociationType.Internal}");
query.Columns.Add("(" + qryAssocs.BuildQuery() + ")", colNameAffiliate_AssociationCount); qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Status, aliasAffiliate_Associations_Owner)}='{StatusCurrent}'");
query.Columns.Add("(" + qryAssocs.BuildQuery() + ")", colNameAffiliate_AssociationOwnerCount);
}
if (columns.HasId(SbmAffiliate.Column.AssociationTarget_Count))
{
// Count active associations.
String aliasAffiliate_Associations_Target = "AffAssTarget";
DbQuery qryAssocs = new DbQuery(db.DbmsType);
qryAssocs.Tables.Add((SbmDbDfn.TableIdx.Association).ToString(), aliasAffiliate_Associations_Target);
qryAssocs.Columns.Add("Count(*)");
qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdTarget, aliasAffiliate_Associations_Target)}={SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Id, aliasAffiliate)}");
qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Type, aliasAffiliate_Associations_Target)}!={(int)Sbm.AssociationType.Internal}");
qryAssocs.Filters.Add($"{SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Status, aliasAffiliate_Associations_Target)}='{StatusCurrent}'");
query.Columns.Add("(" + qryAssocs.BuildQuery() + ")", colNameAffiliate_AssociationTargetCount);
} }
//--------------------------------------------------------------- //---------------------------------------------------------------
@@ -1,7 +1,9 @@
using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.TestTools.UnitTesting;
using Sarand.BusinessMgr.Net.Core.Web.Consoles;
using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Helpers; using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Security;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@@ -19,12 +21,16 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App
[TestMethod] [TestMethod]
public void Test_PasswordEncoding() public void Test_PasswordEncoding()
{ {
using (SbmSecurityConsole_Web securityConsole = new SbmSecurityConsole_Web(UserContext))
{
Assert.IsNotNull(BusMgrDatabase); Assert.IsNotNull(BusMgrDatabase);
StringAssert.Matches(BusMgrDatabase.EncodePassword_Hex(""), reHex); StringAssert.Matches(securityConsole.EncodePassword_Hex(""), reHex);
// Iterate using random filename (8.3). // Iterate using random filename (8.3).
for (int i = 0; i < 1000; i++) for (int i = 0; i < 1000; i++)
StringAssert.Matches(BusMgrDatabase.EncodePassword_Hex(Path.GetRandomFileName()), reHex); StringAssert.Matches(securityConsole.EncodePassword_Hex(Path.GetRandomFileName()), reHex);
}
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
@@ -34,11 +40,14 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App
Assert.IsNotNull(BusMgrDatabase); Assert.IsNotNull(BusMgrDatabase);
Dictionary<string, string> passwordHashes = new Dictionary<string, string>(); Dictionary<string, string> passwordHashes = new Dictionary<string, string>();
using (SbmSecurityConsole_Web securityConsole = new SbmSecurityConsole_Web(UserContext))
{
// Iterate using random filename (8.3). // Iterate using random filename (8.3).
for (int i = 0; i < 200; i++) for (int i = 0; i < 200; i++)
{ {
string password = Path.GetRandomFileName(); string password = Path.GetRandomFileName();
string passwordHash = BusMgrDatabase.EncodePassword_Hex(password); string passwordHash = securityConsole.EncodePassword_Hex(password);
StringAssert.Matches(passwordHash, reHex); StringAssert.Matches(passwordHash, reHex);
passwordHashes.Add(password, passwordHash); passwordHashes.Add(password, passwordHash);
} }
@@ -46,7 +55,8 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App
{ {
string passwordHash = passwordHashes.GetValueOrDefault(password); string passwordHash = passwordHashes.GetValueOrDefault(password);
StringAssert.Matches(passwordHash, reHex); StringAssert.Matches(passwordHash, reHex);
Assert.IsTrue(BusMgrDatabase.ComparePassword_Hex(password, passwordHash)); Assert.IsTrue(securityConsole.ComparePassword_Hex(password, passwordHash));
}
} }
} }
@@ -55,23 +55,6 @@ namespace Sarand.BusinessMgr.Web.Portal.App
public SysId ControlOwnerId { get; protected set; } public SysId ControlOwnerId { get; protected set; }
public SysId ControlRepositoryId { get; protected set; } public SysId ControlRepositoryId { get; protected set; }
} }
private class SessionContextData_Core : SessionContextData
{
// Instance configuration for core database instance without Control configuration.
public SessionContextData_Core(SbmSessionContext_Web sessionContext) : base(sessionContext)
{
}
private SbmInstanceConfig instanceConfig = null;
public override SbmInstanceConfig InstanceConfig
{
get
{
if (instanceConfig == null)
instanceConfig = new SbmInstanceConfig_Core(SessionContext);
return instanceConfig;
}
}
}
private class SessionContextData_Control : SessionContextData private class SessionContextData_Control : SessionContextData
{ {
public SessionContextData_Control(SbmSessionContext_Web sessionContext, SysId controlOwnerId, SysId controlRepositoryId) : base(sessionContext) public SessionContextData_Control(SbmSessionContext_Web sessionContext, SysId controlOwnerId, SysId controlRepositoryId) : base(sessionContext)
@@ -233,26 +216,6 @@ namespace Sarand.BusinessMgr.Web.Portal.App
controlDatabase = SacsDatabaseConsole.OpenOdbcDatabase(odbcConfig); controlDatabase = SacsDatabaseConsole.OpenOdbcDatabase(odbcConfig);
if (controlDatabase.HasErrorState()) if (controlDatabase.HasErrorState())
SaLogger.Warn($"{SysUtil.Fn} Control Database initialisation error: " + controlDatabase.ErrorStateMessage); SaLogger.Warn($"{SysUtil.Fn} Control Database initialisation error: " + controlDatabase.ErrorStateMessage);
// Configure BusMgr database connections.
foreach (Net.Core.Web.App.SbmAppConfig.DatabaseConfig dbConfig in AppConfig.BusMgrDatabases)
{
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
config.Location = dbConfig.Location;
config.User = dbConfig.User;
config.Password = dbConfig.Password;
SacsDatabase coreDatabase = SacsDatabaseConsole.OpenOdbcDatabase(config);
if (!coreDatabase.HasErrorState())
{
// Session context.
ushort sessionContextIdx = sessionContextIdx_Next++;
SessionContextData sessionContextData = new SessionContextData_Core(new SbmSessionContext_Web(sessionContextIdx, Sbm.Application.WebPortal));
sessionContextData.BusMgrDatabase = coreDatabase;
sessionContextData.RepositoryContexts.UnionWith(dbConfig.Identifiers);
sessionContexts.Add(sessionContextData.SessionContext.Index, sessionContextData);
}
else SaLogger.Warn($"{SysUtil.Fn} Database: " + coreDatabase.DatabaseName + ". Initialisation error: " + coreDatabase.ErrorStateMessage);
}
} }
catch (Exception exc) catch (Exception exc)
{ {
@@ -10,7 +10,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Consoles
{ {
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Data members. // Data members.
private SaUpdateLogConsole updateLogConsole; //private SaUpdateLogConsole updateLogConsole;
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Construction. // Construction.
@@ -33,6 +33,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
//------------------------------------------------------------------- //-------------------------------------------------------------------
[HttpGet] [HttpGet]
[Route("Commodity")]
[Route("Commodities")]
public IActionResult Index(Model_Commodity model) public IActionResult Index(Model_Commodity model)
{ {
if (!ValidUserSession) if (!ValidUserSession)
@@ -234,7 +234,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
ColumnDfn colPhoneMobile = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneMobile); ColumnDfn colPhoneMobile = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneMobile);
ColumnDfn colPhoneDirect = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneDirect); ColumnDfn colPhoneDirect = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneDirect);
ColumnDfn colEmail = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Email); ColumnDfn colEmail = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Email);
ColumnDfn colAssocCount = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Association_Count); ColumnDfn colAssocOwnerCount = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.AssociationOwner_Count);
ColumnDfn colAssocTargetCount = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.AssociationTarget_Count);
ColumnDfn colNotes = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Notes); ColumnDfn colNotes = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Notes);
ColumnDfn colStatus = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Status); ColumnDfn colStatus = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Status);
ColumnDfn colCreatedOn = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.CreateOn_Date); ColumnDfn colCreatedOn = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.CreateOn_Date);
@@ -242,7 +243,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
List<ColumnDfn> columns = new List<ColumnDfn>() List<ColumnDfn> columns = new List<ColumnDfn>()
{ {
colId, colName, colAffiliateType, colId, colName, colAffiliateType,
colAddress, colContact, colPhoneMain, colPhoneAlt, colPhoneMobile, colPhoneDirect, colEmail, colAssocCount, colAddress, colContact, colPhoneMain, colPhoneAlt, colPhoneMobile, colPhoneDirect, colEmail, colAssocOwnerCount, colAssocTargetCount,
colNotes, colStatus, colCreatedOn, colUpdatedOn colNotes, colStatus, colCreatedOn, colUpdatedOn
}; };
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Address}")) if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Address}"))
@@ -250,7 +251,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Email}")) if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Email}"))
columns.Remove(colEmail); columns.Remove(colEmail);
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Associations}")) if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Associations}"))
columns.Remove(colAssocCount); columns.Remove(colAssocOwnerCount);
// Sort Columns. // Sort Columns.
if (!prmAffiliate.SortColumns.Any()) if (!prmAffiliate.SortColumns.Any())
@@ -279,7 +280,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
affiliateData.Field.Value.Add($"{Model_Contact.ItemField.Status}", SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))); affiliateData.Field.Value.Add($"{Model_Contact.ItemField.Status}", SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)));
affiliateData.Field.Value.Add($"{Model_Contact.ItemField.CreatedOn}", Localiser.FormatDate(values.GetDate(colCreatedOn.DataName))); affiliateData.Field.Value.Add($"{Model_Contact.ItemField.CreatedOn}", Localiser.FormatDate(values.GetDate(colCreatedOn.DataName)));
affiliateData.Field.Value.Add($"{Model_Contact.ItemField.UpdatedOn}", Localiser.FormatDate(values.GetDate(colUpdatedOn.DataName))); affiliateData.Field.Value.Add($"{Model_Contact.ItemField.UpdatedOn}", Localiser.FormatDate(values.GetDate(colUpdatedOn.DataName)));
long assocCount = values.GetLong(colAssocCount.DataName); long assocOwnerCount = values.GetLong(colAssocOwnerCount.DataName);
long assocTargetCount = values.GetLong(colAssocTargetCount.DataName);
long assocCount = assocOwnerCount + assocTargetCount;
if (assocCount > 0) if (assocCount > 0)
affiliateData.AssociationCount = assocCount; affiliateData.AssociationCount = assocCount;
// Cleanse item values. // Cleanse item values.
@@ -33,6 +33,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
//------------------------------------------------------------------- //-------------------------------------------------------------------
[HttpGet] [HttpGet]
[Route("Contact")]
[Route("Contacts")]
public IActionResult Index(Model_Contact model) public IActionResult Index(Model_Contact model)
{ {
if (!ValidUserSession) if (!ValidUserSession)
@@ -24,6 +24,10 @@ using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm.Config.Database;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control; using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Net.Core.Web.Helpers; using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Web.Portal.Helpers; using Sarand.BusinessMgr.Web.Portal.Helpers;
using DocumentFormat.OpenXml.EMMA;
using DocumentFormat.OpenXml.Wordprocessing;
using Sarand.BusinessMgr.Net.Core.Web.Models;
using Sarand.BusinessMgr.Web.Portal.Models;
namespace Sarand.BusinessMgr.Web.Portal.Controllers namespace Sarand.BusinessMgr.Web.Portal.Controllers
{ {
@@ -218,6 +222,26 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
base.OnActionExecuted(filterContext); base.OnActionExecuted(filterContext);
} }
//-------------------------------------------------------------------
// Model.
/// <summary>
/// Populate model wioth session data etc.
/// <para>- Invoked from SbmController_Web.OnActionExecuting.</para>
/// </summary>
/// <param name="model"></param>
protected override void RefreshModel(SbmModel_Base model)
{
if (model == null) return;
base.RefreshModel(model);
SbmModel_Portal portalModel = model as SbmModel_Portal;
if (portalModel != null)
{
// Populate menu options.
portalModel.PopulateMenu();
}
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Keep Logged In. // Keep Logged In.
//------------------------------------------------------------------- //-------------------------------------------------------------------
@@ -238,12 +262,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", "."); String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", ".");
if (keepLoggedInParams.IsValid()) if (keepLoggedInParams.IsValid())
{ {
// User may be defined on any one of the BusinessMgr databases - need to find out which. // Instance Repository configured on Control database identified by Context.
// Identify session contexts with a BusMgr database that hosts the specified email address. SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(keepLoggedInParams.RepositoryContext);
List<SbmSessionContext> sessionContexts = SbmSessionContextHelper_Portal.GetSessionContextForRepositoryContextUserEmail(keepLoggedInParams.RepositoryContext, keepLoggedInParams.EmailAddress); if (sessionContext != null)
if (sessionContexts.Any())
{
foreach (SbmSessionContext sessionContext in sessionContexts)
{ {
// Consoles and Managers must be associated with the specific context. // Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext); SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
@@ -277,9 +298,6 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers
else SaLogger.Warn(logPrefix + "Security Item or Affiliate not found. " + logSuffix); else SaLogger.Warn(logPrefix + "Security Item or Affiliate not found. " + logSuffix);
} }
} }
if (ValidUserSession)
break;
}
} }
else SaLogger.Warn($"{SysUtil.Fn} Keep Logged In cookie found but no matching session contexts found." + logSuffix); else SaLogger.Warn($"{SysUtil.Fn} Keep Logged In cookie found but no matching session contexts found." + logSuffix);
} }
@@ -69,30 +69,12 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
// Instance Repository configured on Control database. // Instance Repository configured on Control database.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext); SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext);
String errorMessage = ""; String errorMessage = "";
if (!OpenUserSession(model, sessionContext, ref errorMessage)) if (!OpenUserSession(model, sessionContext, ref errorMessage))
{ {
if (!StringUtil.IsBlank(errorMessage)) if (!StringUtil.IsBlank(errorMessage))
return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage)); return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage));
} }
} }
if (!(SessionData_Portal?.ValidUser ?? false))
{
// Session contexts with a BusMgr database that hosts the specified email address.
List<SbmSessionContext> sessionContexts = SbmSessionContextHelper_Portal.GetSessionContextForRepositoryContextUserEmail(model.RepositoryContext, model.EmailAddress);
if (sessionContexts.IsEmpty())
return Json(responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]));
foreach (SbmSessionContext sessionContext in sessionContexts)
{
String errorMessage = "";
if (OpenUserSession(model, sessionContext, ref errorMessage)) break;
if (!StringUtil.IsBlank(errorMessage))
return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage));
}
}
} }
if (!(SessionData_Portal?.ValidUser ?? false)) if (!(SessionData_Portal?.ValidUser ?? false))
@@ -125,14 +107,14 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
disposables.Add(accountMgrForUser); disposables.Add(accountMgrForUser);
// User's security item. // User's security item.
SaSecurityItem securityItemUser = GetSecurityItemForSignin(securityConsoleForUser, model); SaSecurityItem securityItemUser = GetSecurityItemForSignin(userContext, securityConsoleForUser, model);
disposables.Add(securityItemUser); disposables.Add(securityItemUser);
if (securityItemUser == null) if (securityItemUser == null)
{ {
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}."); SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}.");
return false; return false;
} }
if (!securityConsoleForUser.PasswordMatches(securityItemUser, model.Password)) if (!securityConsoleForUser.PasswordMatches(securityItemUser, model.Password, userContext.DbUpdateInfo))
{ {
SaLogger.Warn($"{SysUtil.Fn} Supplied password doesn't match Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}."); SaLogger.Warn($"{SysUtil.Fn} Supplied password doesn't match Security Item. Database: {busMgrDatabase.DatabaseName}. Email: {model.EmailAddress}.");
return false; return false;
@@ -182,7 +164,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
} }
//------------------------------------------------------------------- //-------------------------------------------------------------------
private SaSecurityItem GetSecurityItemForSignin(SaSecurityConsole securityConsoleForUser, Model_Security model) private SaSecurityItem GetSecurityItemForSignin(SbmUserContext_Web userContext, SaSecurityConsole securityConsoleForUser, Model_Security model)
{ {
// Retrieve security item by email address. // Retrieve security item by email address.
SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(model.EmailAddress); SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(model.EmailAddress);
@@ -198,7 +180,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
// Record invalid login attempt. // Record invalid login attempt.
securityItemUser.InvalidLoginCount++; securityItemUser.InvalidLoginCount++;
securityItemUser.LastInvalidLoginAt = DateTime.Now; securityItemUser.LastInvalidLoginAt = DateTime.Now;
if (!securityConsoleForUser.UpdateSecurityItem(securityItemUser, DbUpdateInfo)) if (!securityConsoleForUser.UpdateSecurityItem(securityItemUser, userContext.DbUpdateInfo))
SaLogger.Warn($"{SysUtil.Fn} Failed to store invalid sign-in attempt against User: {model.EmailAddress}. {AccountMgr.ErrorStateMessage}", true); SaLogger.Warn($"{SysUtil.Fn} Failed to store invalid sign-in attempt against User: {model.EmailAddress}. {AccountMgr.ErrorStateMessage}", true);
SaLogger.Warn($"{SysUtil.Fn} Attempt to sign-in to User {model.EmailAddress} with invalid password. Attempt: {securityItemUser.InvalidLoginCount}.", true); SaLogger.Warn($"{SysUtil.Fn} Attempt to sign-in to User {model.EmailAddress} with invalid password. Attempt: {securityItemUser.InvalidLoginCount}.", true);
securityItemUser.Dispose(); securityItemUser = null; securityItemUser.Dispose(); securityItemUser = null;
@@ -410,15 +392,14 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
RequestPasswordParams storePasswordParams = ExtractRequestPasswordLinkParams(model.rpe); RequestPasswordParams storePasswordParams = ExtractRequestPasswordLinkParams(model.rpe);
if (storePasswordParams.IsValid()) if (storePasswordParams.IsValid())
{ {
// User may be defined on any one of the BusinessMgr databases - need to find out which. // Instance Repository configured on Control database identified by Context.
// Identify session contexts for databases with specified Id that hosts the specified email address. SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(storePasswordParams.RepositoryContext);
List<SbmSessionContext> sessionContexts = SbmSessionContextHelper_Portal.GetSessionContextForRepositoryContextUserEmail(storePasswordParams.RepositoryContext, storePasswordParams.EmailAddress); if (sessionContext != null)
foreach (SbmSessionContext sessionContext in sessionContexts)
{ {
// Consoles and Managers must be associated with the specific context. // Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext); SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContextForUser)) using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContextForUser)) using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{ {
// Retrieve user details and validate email address. // Retrieve user details and validate email address.
securityItemUser = securityConsoleForUser.GetSecurityItemById(SaSecurity.ItemType.User, storePasswordParams.SecurityItemId); securityItemUser = securityConsoleForUser.GetSecurityItemById(SaSecurity.ItemType.User, storePasswordParams.SecurityItemId);
@@ -429,7 +410,6 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
userContextForUser = userContext; userContextForUser = userContext;
validRequestPasswordParams = true; validRequestPasswordParams = true;
validSessionRequired = false; validSessionRequired = false;
break;
} }
else else
{ {
@@ -471,7 +451,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
String oldPasswordHashed = securityItemUser.PasswordHash; String oldPasswordHashed = securityItemUser.PasswordHash;
// Store password. // Store password.
securityItemUser.PasswordHash = SbmPasswordHelper.GetPasswordHash(securityItemUser, model.Password); // NB Do not use Microsoft.AspNetCore.Identity.PasswordHasher.HashPassword() while legacy (C++) desktop application still in use.
securityConsole.SetPassword(securityItemUser, model.Password);
securityItemUser.PasswordChangedAt = DateTime.Now; securityItemUser.PasswordChangedAt = DateTime.Now;
// Remove new password from history if present. // Remove new password from history if present.
for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++) for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++)
@@ -489,7 +470,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
securityItemUser.PasswordHistory.Add(oldPasswordHashed); securityItemUser.PasswordHistory.Add(oldPasswordHashed);
while (securityItemUser.PasswordHistory.Count > 10) while (securityItemUser.PasswordHistory.Count > 10)
securityItemUser.PasswordHistory.RemoveAt(securityItemUser.PasswordHistory.Count - 1); securityItemUser.PasswordHistory.RemoveAt(securityItemUser.PasswordHistory.Count - 1);
if (!securityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo)) if (!securityConsole.UpdateSecurityItem(securityItemUser, userContextForUser?.DbUpdateInfo ?? DbUpdateInfo))
{ {
SaLogger.Warn($"{SysUtil.Fn} Failed to change password for {securityItemUser.EmailAddress}: {securityConsole.ErrorStateMessage}"); SaLogger.Warn($"{SysUtil.Fn} Failed to change password for {securityItemUser.EmailAddress}: {securityConsole.ErrorStateMessage}");
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"])); return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
@@ -537,9 +518,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
model.ValidateRequestPasswordData(responseData); model.ValidateRequestPasswordData(responseData);
if (responseData.HasControlErrors()) return Json(responseData); if (responseData.HasControlErrors()) return Json(responseData);
// Identify session contexts with a BusMgr database that hosts the specified email address. // Instance Repository configured on Control database identified by Context.
List<SbmSessionContext> sessionContexts = SbmSessionContextHelper_Portal.GetSessionContextForRepositoryContextUserEmail(model.RepositoryContext, model.EmailAddress); SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext);
foreach (SbmSessionContext sessionContext in sessionContexts) if (sessionContext != null)
{ {
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext); SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
@@ -76,10 +76,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{ {
String logPrefix = $"{SysUtil.Fn} 'Request Password' parameters supplied but "; String logPrefix = $"{SysUtil.Fn} 'Request Password' parameters supplied but ";
String logSuffix = changePasswordParams.GetValidParams().Concat("", " ", "."); String logSuffix = changePasswordParams.GetValidParams().Concat("", " ", ".");
// User may be defined on any one of the BusinessMgr databases - need to find out which. // Instance Repository configured on Control database identified by Context.
// Identify session contexts with a BusMgr database that hosts the specified email address. SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(changePasswordParams.RepositoryContext);
List<SbmSessionContext> sessionContexts = SbmSessionContextHelper_Portal.GetSessionContextForRepositoryContextUserEmail(changePasswordParams.RepositoryContext, changePasswordParams.EmailAddress); if (sessionContext != null)
foreach (SbmSessionContext sessionContext in sessionContexts)
{ {
// Consoles and Managers must be associated with the specific context. // Consoles and Managers must be associated with the specific context.
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext); SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
@@ -99,7 +98,6 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{ {
model.rpe = encryptedParams; model.rpe = encryptedParams;
validSessionRequired = false; validSessionRequired = false;
break;
} }
else SaLogger.Warn(logPrefix + "Security Item and Affiliate are incompatible with parameters. " + logSuffix); else SaLogger.Warn(logPrefix + "Security Item and Affiliate are incompatible with parameters. " + logSuffix);
} }
@@ -63,6 +63,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Helpers
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Session Contexts for Repository Context and User Email Address. // Session Contexts for Repository Context and User Email Address.
//------------------------------------------------------------------- //-------------------------------------------------------------------
[Obsolete("Deprecated - BusMgr databases only referenced via Control database rather than in application config.")]
/// <summary> /// <summary>
/// Identify the session context(s) that corresponds with the BusinessMgr /// Identify the session context(s) that corresponds with the BusinessMgr
/// repository by context for the specified user by email address. /// repository by context for the specified user by email address.
@@ -40,6 +40,60 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
public bool UserCanCreateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(itemType); } public bool UserCanCreateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile_Core.UserCanCreateItemType(itemType); }
public bool UserCanUpdateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(itemType); } public bool UserCanUpdateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile_Core.UserCanUpdateItemType(itemType); }
//-------------------------------------------------------------------
// Page menu options.
public class MenuOptionData
{
public String Caption { get; set; }
public String Page { get; set; }
}
public class MenuItemData
{
public String Caption { get; set; }
public List<MenuOptionData> Options { get; } = new List<MenuOptionData>();
}
public class MenuData
{
public List<MenuItemData> Items { get; } = new List<MenuItemData>();
}
public MenuData Menu { get; set; }
/// <summary>
/// Populate available menu options for the page.
/// <para>- Invoked from SbmController_Portal.OnActionExecuting.</para>
/// </summary>
public void PopulateMenu()
{
Menu = new MenuData();
// Contacts.
MenuItemData contactsItem = new MenuItemData() { Caption = @Localiser["label.contacts"] };
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.contacts"], Page = "Contacts" });
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.customers"], Page = "Customers" });
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.suppliers"], Page = "Suppliers" });
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.associations"], Page = "Associations" });
if (contactsItem.Options.Any())
Menu.Items.Add(contactsItem);
// Commodities.
MenuItemData commoditiesItem = new MenuItemData() { Caption = @Localiser["label.commodities"] };
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.commodities"], Page = "Commodity" });
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["caption.asset.categories"], Page = "Assets/AssetCategory" });
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.assets"], Page = "Assets/Asset" });
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["caption.vehicle.classes"], Page = "Assets/VehicleClass" });
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.vehicles"], Page = "Assets/Vehicle" });
if (commoditiesItem.Options.Any())
Menu.Items.Add(commoditiesItem);
// Reference.
MenuItemData referenceItem = new MenuItemData() { Caption = @Localiser["label.reference"] };
referenceItem.Options.Add(new MenuOptionData() { Caption = @Localiser["caption.code.types"], Page = "Codes/CodeType" });
referenceItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.codes"], Page = "Codes/Code" });
if (referenceItem.Options.Any())
Menu.Items.Add(referenceItem);
}
//------------------------------------------------------------------- //-------------------------------------------------------------------
// View reference data. // View reference data.
@@ -40,13 +40,6 @@
@* Filter Panel *@ @* Filter Panel *@
<div class="sbm-panel-filter"> <div class="sbm-panel-filter">
<div class="row"> <div class="row">
<div class="col-sm-4 row pb4">
@* Commodity filter - code, description etc *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-7 col-sm-8">
@Html.TextBox("Filter.Search", "", new { @id = "", @class = "FilterCommodity sbm-input", @maxlength = "32" })
</div>
</div>
<div class="col-sm-4 row pb4"> <div class="col-sm-4 row pb4">
@* Commodity Category *@ @* Commodity Category *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div> <div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.type"]</div>
@@ -54,6 +47,13 @@
@Html.DropDownList("Filter.CommodityType", Model.GetCommodityTypeCodesForSelect(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" }) @Html.DropDownList("Filter.CommodityType", Model.GetCommodityTypeCodesForSelect(), Localiser["label.any"], new { @id = "", @class = "FilterCommodityType sbm-select" })
</div> </div>
</div> </div>
<div class="col-sm-4 row pb4">
@* Commodity filter - code, description etc *@
<div class="col-4 col-sm-4 sbm-label text-left text-sm-right">@Localiser["label.search"]</div>
<div class="col-7 col-sm-8">
@Html.TextBox("Filter.Search", "", new { @id = "", @class = "FilterSearch sbm-input", @maxlength = "32" })
</div>
</div>
<div class="col-sm-4 row pb4"> <div class="col-sm-4 row pb4">
</div> </div>
</div> </div>
@@ -118,39 +118,21 @@
</li> </li>
} }
else else
{
@foreach (var menuItem in Model.Menu.Items)
{ {
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.contacts"] @(menuItem.Caption)
</a> </a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown"> <div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Contact');">@Localiser["label.contacts"]</div> @foreach (var menuOption in menuItem.Options)
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Customers');">@Localiser["label.customers"]</div> {
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Suppliers');">@Localiser["label.suppliers"]</div> <div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('@(menuOption.Page)');">@(menuOption.Caption)</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Association');">@Localiser["label.associations"]</div> }
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.commodities"]
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Commodity');">@Localiser["label.commodities"]</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Assets/AssetCategory');">@Localiser["caption.asset.categories"]</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Assets/Asset');">@Localiser["label.assets"]</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Assets/VehicleClass');">@Localiser["caption.vehicle.classes"]</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Assets/Vehicle');">@Localiser["label.vehicles"]</div>
</div>
</li>
<li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.reference"]
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Codes/CodeType');">@Localiser["caption.code.types"]</div>
<div class="dropdown-item text-dark sbm-action" onclick="sbm.goToPage('Codes/Code');">@Localiser["label.codes"]</div>
</div> </div>
</li> </li>
}
<li class="nav-item dropdown"> <li class="nav-item dropdown">
<a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link text-dark dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@Localiser["label.security"] @Localiser["label.security"]
@@ -8,38 +8,6 @@
"User": "sapphire", "User": "sapphire",
"Password": "sarand" "Password": "sarand"
}, },
"BusMgrDatabases": [
{
"Identifiers": [ "Sarand" ],
"Location": "MsSql:Roman\\SQL2016.SaBusinessMgr_Sarand_Dev",
"User": "sapphire",
"Password": "sarand"
},
{
"Identifiers": [ "Cadix" ],
"Location": "MsSql:Roman\\SQL2016.SaBusinessMgr_Cadix",
"User": "sapphire",
"Password": "sarand"
},
{
"Identifiers": [ "BPE" ],
"Location": "MsSql:Roman\\SQL2016.SaBusinessMgr_BPE",
"User": "sapphire",
"Password": "sarand"
},
{
"Identifiers": [ "MIMO" ],
"Location": "MsSql:.\\SQL2016.SaBusinessMgr_Mimo",
"User": "sapphire",
"Password": "sarand"
},
{
"Identifiers": [ "Firtree-X" ],
"Location": "MsSql:Sarand110\\SQL2016.SaBusinessMgr_Firtree",
"User": "firtree",
"Password": "sarand"
}
],
"Email": { "Email": {
"Context": "SBM-Dev", "Context": "SBM-Dev",
"ContactUs": { "ContactUs": {
@@ -183,7 +183,8 @@
co.storeItem = function (env) co.storeItem = function (env)
{ {
env.ajax.storeItem = env.ajax.storeItem || { env.ajax.storeItem = env.ajax.storeItem || {
url: sbm.url.base + 'Commodity/Ajax/StoreItem', formSel: env.$frm.item, callbackFn: function (response) { co.onStoreItem(env, response); } }; url: sbm.url.base + 'Commodity/Ajax/StoreItem', formSel: env.$frm.item, callbackFn: function (response) { co.onStoreItem(env, response); }
};
sbm.doAjaxRequest(env.ajax.storeItem, 50); sbm.doAjaxRequest(env.ajax.storeItem, 50);
} }
co.onStoreItem = function (env, response) co.onStoreItem = function (env, response)
@@ -268,7 +269,7 @@
env.$pnl.tmpls = env.$pnl.items.find('.sbm-panel-item-template'); env.$pnl.tmpls = env.$pnl.items.find('.sbm-panel-item-template');
env.$frm.filter = $('#frmCommodityFilter'); env.$frm.filter = $('#frmCommodityFilter');
env.$frm.filter.on('input', '.FilterSearch', function () { co.refreshResults(250); }).on('change', '.FilterCommodityType,.FilterStatusCat', function () { co.refreshResults(50); }); env.$frm.filter.on('input', '.FilterSearch', function () { co.refreshResults(env, 250); }).on('change', '.FilterCommodityType,.FilterStatusCat', function () { co.refreshResults(env, 50); });
var opt = sbm.dlgOpts(); var opt = sbm.dlgOpts();
opt.dialogClass += " sbm-Commodity"; opt.dialogClass += " sbm-Commodity";
env.$dlg.item = $('#dlgCommodity').dialog(opt); env.$dlg.item = $('#dlgCommodity').dialog(opt);
@@ -169,7 +169,7 @@
} }
sbm.clearItemForm = function ($frm) sbm.clearItemForm = function ($frm)
{ {
//sbm.clearControlErrors($frm); sbm.clearControlErrors($frm);
$('.sbm-input,.sbm-textarea,.sbm-select', $frm).val('').prop('readonly', false).prop('disabled', false); $('.sbm-input,.sbm-textarea,.sbm-select', $frm).val('').prop('readonly', false).prop('disabled', false);
$('.sbm-checkbox', $frm).prop('readonly', false).prop('disabled', false).removeAttr('checked'); $('.sbm-checkbox', $frm).prop('readonly', false).prop('disabled', false).removeAttr('checked');
} }