3.0.0.1 Demo repository registration

This commit is contained in:
Andy Howard
2025-02-08 16:41:08 +00:00
parent 0d8e7d5619
commit c4e5712d0a
312 changed files with 13145 additions and 30232 deletions
@@ -720,4 +720,28 @@
<data name="label.count" xml:space="preserve">
<value>Count</value>
</data>
<data name="caption.register.demo.account" xml:space="preserve">
<value>Register Demo Account</value>
</data>
<data name="caption.request.demo.account" xml:space="preserve">
<value>Request Demo Account</value>
</data>
<data name="label.register" xml:space="preserve">
<value>Register</value>
</data>
<data name="label.request" xml:space="preserve">
<value>Request</value>
</data>
<data name="label.password.confirm" xml:space="preserve">
<value>Password confirm</value>
</data>
<data name="msg.warn.password.invalid" xml:space="preserve">
<value>Password must be a minimum of {0} characters with upper and lower case letters, at least one number and special character unless at least {1} characters long.</value>
</data>
<data name="label.password.current" xml:space="preserve">
<value>Current password</value>
</data>
<data name="label.strength" xml:space="preserve">
<value>Strength</value>
</data>
</root>
@@ -147,7 +147,7 @@ namespace Sarand.BusinessMgr.Web.Portal.App
}
public override ISacsDatabase GetBusMgrDatabase(SbmSessionContext sessionContext)
{
return sessionContexts.GetValue(sessionContext.Index, null)?.BusMgrDatabase;
return sessionContexts.GetValue(sessionContext?.Index ?? 0, null)?.BusMgrDatabase;
}
// Instance configuration.
public override SbmInstanceConfig GetInstanceConfig(SbmSessionContext sessionContext)
@@ -169,47 +169,11 @@ namespace Sarand.BusinessMgr.Web.Portal.App
//-------------------------------------------------------------------
// Create consoles.
public SbmSessionConsole CreateSessionConsole(ISbmUserOrganisationContext userContext)
public SbmDemoInstanceConsole CreateDemoInstanceConsole()
{
return SbmSessionConsole.CreateConsole(userContext);
return new SbmDemoInstanceConsole_Portal(SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(Sbm.RepositoryContext_Demo));
}
public SaDiaryConsole CreateDiaryConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaSecurityConsole CreateSecurityConsole(ISbmUserOrganisationContext userContext)
{
return new SbmSecurityConsole_Web(userContext);
}
public SaCodeTypeConsole CreateCodeTypeConsole(ISbmUserOrganisationContext userContext)
{
return new SbmCodeTypeConsole_Web(userContext);
}
public SaItemDataConsole CreateItemDataConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaItemDocConsole CreateItemDocConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaItemOptionConsole CreateItemOptionConsole(ISbmUserOrganisationContext userContext)
{
return new SbmItemOptionConsole_Web(userContext);
}
public SaInterfaceConsole CreateInterfaceConsole(ISbmUserOrganisationContext userContext)
{
return null;
}
public SaUpdateLogConsole CreateUpdateLogConsole(ISbmUserOrganisationContext userContext)
{
return new SbmUpdateLogConsole_Web(userContext);
}
public SaReferenceDataConsole CreateReferenceDataConsole(ISbmUserOrganisationContext userContext)
{
return new SbmReferenceDataConsole_Portal(userContext);
}
public SbmEmailConsole CreateEmailConsole(ISbmUserOrganisationContext userContext)
public SbmEmailConsole CreateEmailConsole()
{
return new SbmEmailConsole_Portal(EmailConfig);
}
@@ -243,7 +207,7 @@ namespace Sarand.BusinessMgr.Web.Portal.App
// Application configuration.
appConfigs = SbmAppConfigHelper.ExtractAppConfigs(SbmConfiguration.GetSection("AppConfigs"));
emailConfigs = SbmEmailConfigHelper.ExtractEmailConfigs(SbmConfiguration.GetSection("Email/Configs"));
emailConfigs = SbmEmailConfigHelper.ExtractEmailConfigs(SbmConfiguration.GetSection("Email").GetSection("Configs"));
LoggingRootFolder = AppConfig.Logging.RootFolder;
// Application instance.
@@ -306,10 +270,7 @@ namespace Sarand.BusinessMgr.Web.Portal.App
if (owner.IsStatusActive && repository.IsStatusActive)
{
// Configure Core database.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
config.Location = $"MsSql:{repository.ServerName}\\{repository.InstanceName}.{repository.DatabaseName}";
config.User = repository.UserName;
config.Password = repository.Password;
SacsDatabaseConsole.OdbcConfig config = SbmCoreInstanceConsole_Dbas.GetRepositoryOdbcConfig(repository);
SacsDatabase coreDatabase = SacsDatabaseConsole.OpenOdbcDatabase(config);
if (!coreDatabase.HasErrorState())
@@ -1,6 +1,7 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Consoles;
using Sarand.BusinessMgr.Net.Core.Web.Control.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Core;
using Sarand.BusinessMgr.Web.Portal.Consoles;
@@ -31,47 +32,47 @@ namespace Sarand.BusinessMgr.Web.Portal.App
//-------------------------------------------------------------------
// Create consoles.
public override SbmSessionConsole CreateSessionConsole(ISbmUserOrganisationContext userContext)
public override SbmSessionConsole CreateSessionConsole(SbmInternals internals)
{
return SbmSessionConsole.CreateConsole(userContext);
return SbmSessionConsole.CreateConsole(internals);
}
public override SaDiaryConsole CreateDiaryConsole(ISbmUserOrganisationContext userContext)
public override SaDiaryConsole CreateDiaryConsole(SbmInternals internals)
{
return null;
}
public override SaSecurityConsole CreateSecurityConsole(ISbmUserOrganisationContext userContext)
public override SaSecurityConsole CreateSecurityConsole(SbmInternals internals)
{
return new SbmSecurityConsole_Web(userContext);
return new SbmSecurityConsole_Web(internals);
}
public override SaCodeTypeConsole CreateCodeTypeConsole(ISbmUserOrganisationContext userContext)
public override SaCodeTypeConsole CreateCodeTypeConsole(SbmInternals internals)
{
return new SbmCodeTypeConsole_Web(userContext);
return new SbmCodeTypeConsole_Web(internals);
}
public override SaItemDataConsole CreateItemDataConsole(ISbmUserOrganisationContext userContext)
public override SaItemDataConsole CreateItemDataConsole(SbmInternals internals)
{
return null;
}
public override SaItemDocConsole CreateItemDocConsole(ISbmUserOrganisationContext userContext)
public override SaItemDocConsole CreateItemDocConsole(SbmInternals internals)
{
return null;
}
public override SaItemOptionConsole CreateItemOptionConsole(ISbmUserOrganisationContext userContext)
public override SaItemOptionConsole CreateItemOptionConsole(SbmInternals internals)
{
return new SbmItemOptionConsole_Web(userContext);
return new SbmItemOptionConsole_Web(internals);
}
public override SaInterfaceConsole CreateInterfaceConsole(ISbmUserOrganisationContext userContext)
public override SaInterfaceConsole CreateInterfaceConsole(SbmInternals internals)
{
return new SbmInterfaceConsole_Web(userContext);
return new SbmInterfaceConsole_Web(internals);
}
public override SaUpdateLogConsole CreateUpdateLogConsole(ISbmUserOrganisationContext userContext)
public override SaUpdateLogConsole CreateUpdateLogConsole(SbmInternals internals)
{
return new SbmUpdateLogConsole_Web(userContext);
return new SbmUpdateLogConsole_Web(internals);
}
public override SaReferenceDataConsole CreateReferenceDataConsole(ISbmUserOrganisationContext userContext)
public override SaReferenceDataConsole CreateReferenceDataConsole(SbmInternals internals)
{
return new SbmReferenceDataConsole_Portal(userContext);
return new SbmReferenceDataConsole_Portal(internals);
}
public override SbmEmailConsole CreateEmailConsole(ISbmUserOrganisationContext userContext, SbmEmailConfig emailConfig)
public override SbmEmailConsole CreateEmailConsole(SbmEmailConfig emailConfig)
{
return new SbmEmailConsole_Portal(emailConfig);
}
@@ -108,7 +108,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
// Properties.
// Business components.
protected SbmSysParamCache SysParamCache { get { if (sysParamCache == null) sysParamCache = new SbmSysParamCache(UserContext_Core, SessionData_Portal.User.AffiliateId); return sysParamCache; } }
protected SbmSysParamCache SysParamCache { get { if (sysParamCache == null) sysParamCache = new SbmSysParamCache(Internals, SessionData_Portal.User.AffiliateId); return sysParamCache; } }
//-------------------------------------------------------------------
// User Session.
@@ -317,7 +317,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
if (keepLoggedInParams.IsValid())
{
// Instance Repository configured on Control database identified by Context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(keepLoggedInParams.RepositoryContext);
SbmSessionContext sessionContext = SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(keepLoggedInParams.RepositoryContext);
if (sessionContext != null)
{
// Consoles and Managers must be associated with the specific context.
@@ -390,7 +390,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
// NB - 'Keep Logged In' is termed 'Remember Me' in the Portal application.
public static class KeepLoggedIn
{
public static string CookieName = "sbprm";
public static string CookieName = "BMKLI";
public static string Base64Key = SacsEncryptionHelper.EncodePlainKey("<=SaBusMgr^P0rt4L{KeepLoggedIn}~", SacsEncryptionHelper.KeyLength);
//private static String KeepLoggedIn.Base64IV_Generated = SacsEncryptionHelper.InitSymmetricEncryptionIV(KeepLoggedIn.Base64Key);
public static string Base64IV = "m47AMcMgACp3aoQVc0Y92A==";
@@ -461,7 +461,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
keepLoggedInParams.AffiliateIdUser = SysId.ToSysId(linkParams.Get(ParamName_KeepLoggedIn_AffiliateIdUser));
keepLoggedInParams.AssociationIdOrganisation = SysId.ToSysId(linkParams.Get(ParamName_KeepLoggedIn_AssociationIdOrganisation));
}
if (DebugMode) SaLogger.Info($"{SysUtil.Fn} UserAccountId: {SysId.ToString(keepLoggedInParams.AffiliateIdUser)}");
if (DebugMode && SysId.IsValid(keepLoggedInParams.AffiliateIdUser)) SaLogger.Info($"{SysUtil.Fn} UserAccountId: {SysId.ToString(keepLoggedInParams.AffiliateIdUser)}");
return keepLoggedInParams;
}
@@ -0,0 +1,54 @@
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Dbas.Consoles;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Dbas.Base;
namespace Sarand.BusinessMgr.Web.Portal.Components
{
public class SbmCoreInstanceConsole_Portal : SbmCoreInstanceConsole_Dbas
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private class DataMembers
{
public DataMembers(SbmSessionContext sessionContext)
{
this.SessionContext = sessionContext;
}
public SbmSessionContext SessionContext { get; }
public SbmInternals Internals { get; set; }
}
private DataMembers mbr { get; }
//-------------------------------------------------------------------
// Construction.
public SbmCoreInstanceConsole_Portal(SbmSessionContext sessionContext)
{
mbr = new DataMembers(sessionContext);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (mbr.Internals != null) mbr.Internals.Dispose();
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
private static SbmApplication_Portal App_Portal { get { return SbmApplication_Portal.Instance; } }
public override SbmInternals Internals { get { if (mbr.Internals == null) { mbr.Internals = new SbmInternals(mbr.SessionContext); } return mbr.Internals; } }
//-------------------------------------------------------------------
// Utilities.
//-------------------------------------------------------------------
}
}
@@ -17,10 +17,8 @@ using Sarand.Net.Standard.Base.ReferenceData;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.UpdateLog;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm;
namespace Sarand.BusinessMgr.Web.Portal.Components
{
@@ -51,16 +49,17 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
// Properties.
protected SbmSessionData_Portal SessionData_Portal { get { return SessionData_Web as SbmSessionData_Portal; } }
public string OrganisationName { get { return SessionData_Portal?.Organisation?.DisplayName ?? ""; } }
protected override SbmInstanceSchemaConsole InstanceSchemaConsole { get { return Internals.InstanceSchemaConsole; } }
//-------------------------------------------------------------------
// Security profile.
public bool UserCanViewFinancials() { return SessionData_Portal.SecurityProfile.UserCanViewFinancials(); }
public bool UserCanViewCommodityFinancials_Supply() { return SessionData_Portal.SecurityProfile.UserCanViewFinancials(FinancialType.CommoditySupply); }
public bool UserCanViewCommodityFinancials_Sales() { return SessionData_Portal.SecurityProfile.UserCanViewFinancials(FinancialType.CommoditySales); }
public bool UserCanViewCommodityFinancials_Supply() { return SessionData_Portal.SecurityProfile.UserCanViewFinancials(Sbm.FinancialType.CommoditySupply); }
public bool UserCanViewCommodityFinancials_Sales() { return SessionData_Portal.SecurityProfile.UserCanViewFinancials(Sbm.FinancialType.CommoditySales); }
public bool UserCanUpdateFinancials() { return SessionData_Portal.SecurityProfile.UserCanUpdateFinancials(); }
public bool UserCanStockTake() { return SessionData_Portal.SecurityProfile.UserHasSecurityRight(SecurityRight.StockTake); }
public bool UserCanCreateItem(ItemType itemType) { return SessionData_Portal.SecurityProfile.UserCanCreateItemType(itemType); }
public bool UserCanUpdateItem(ItemType itemType) { return SessionData_Portal.SecurityProfile.UserCanUpdateItemType(itemType); }
public bool UserCanStockTake() { return SessionData_Portal.SecurityProfile.UserHasSecurityRight(Sbm.SecurityRight.StockTake); }
public bool UserCanCreateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile.UserCanCreateItemType(itemType); }
public bool UserCanUpdateItem(Sbm.ItemType itemType) { return SessionData_Portal.SecurityProfile.UserCanUpdateItemType(itemType); }
//-------------------------------------------------------------------
// Business components.
@@ -90,7 +89,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
protected SbmStockControlConfig StockControlConfig { get { return Internals.StockControlConfig; } }
protected SbmRequirementCostingConfig RequirementCostingConfig { get { return Internals.RequirementCostingConfig; } }
// System codes.
protected List<TypeCodeDesc> GetCodesOfType(SystemCode systemCode) { return Internals.GetSystemCodes(systemCode); }
protected List<TypeCodeDesc> GetCodesOfType(Sbm.SystemCode systemCode) { return Internals.GetSystemCodes(systemCode); }
//-------------------------------------------------------------------
// Page menu options.
@@ -122,7 +121,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
// Contacts.
MenuItemData contactsItem = new MenuItemData() { Caption = @Localiser["label.contacts"] };
if (SessionConsole.AllowOption(ConfigOption.Contacts))
if (SessionConsole.AllowOption(Sbm.ConfigOption.Contacts))
{
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.contacts"], Page = "Contacts" });
contactsItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.customers"], Page = "Customers" });
@@ -134,13 +133,13 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
// Commodities.
MenuItemData commoditiesItem = new MenuItemData() { Caption = @Localiser["label.commodities"] };
if (SessionConsole.AllowOption(ConfigOption.Commodities))
if (SessionConsole.AllowOption(Sbm.ConfigOption.Commodities))
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.commodities"], Page = "Commodity" });
if (SessionConsole.AllowOption(ConfigOption.Assets))
if (SessionConsole.AllowOption(Sbm.ConfigOption.Assets))
{
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" });
if (SessionConsole.AllowOption(ConfigOption.Vehicles))
if (SessionConsole.AllowOption(Sbm.ConfigOption.Vehicles))
{
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["caption.vehicle.classes"], Page = "Vehicles/VehicleClass" });
commoditiesItem.Options.Add(new MenuOptionData() { Caption = @Localiser["label.vehicles"], Page = "Vehicles/Vehicle" });
@@ -175,7 +174,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
}
/// <summary>List of Code Type Codes for dropdown.</summary>
public IEnumerable<SelectListItem> GetCodeTypeCodesForSelect(ApplCodeType codeType, bool activeOnly = true)
public IEnumerable<SelectListItem> GetCodeTypeCodesForSelect(Sbm.ApplCodeType codeType, bool activeOnly = true)
{
List<CodeDesc> codes = new List<CodeDesc>();
foreach (SaCode code in CodeTypeConsole.GetCodesForCodeType(SbmSystem.GetCodeTypeCode(codeType), activeOnly))
@@ -192,10 +191,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
/// </summary>
public IEnumerable<SelectListItem> GetAffiliateTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> affiliateTypes = GetCodesOfType(SystemCode.AffiliateType);
if (!affiliateTypes.Any(item => item.Type == (int)AffiliateType.AnyOrganisation))
affiliateTypes.Insert(0, new TypeCodeDesc((int)AffiliateType.AnyOrganisation, ((short)AffiliateType.AnyOrganisation).ToString(), Localiser["label.organisation"]));
affiliateTypes.Insert(0, AffiliateType.Any, "", Localiser["label.any"]);
List<TypeCodeDesc> affiliateTypes = GetCodesOfType(Sbm.SystemCode.AffiliateType);
if (!affiliateTypes.Any(item => item.Type == (int)Sbm.AffiliateType.AnyOrganisation))
affiliateTypes.Insert(0, new TypeCodeDesc((int)Sbm.AffiliateType.AnyOrganisation, ((short)Sbm.AffiliateType.AnyOrganisation).ToString(), Localiser["label.organisation"]));
affiliateTypes.Insert(0, Sbm.AffiliateType.Any, "", Localiser["label.any"]);
return new SelectList(affiliateTypes, "Code", "Desc");
}
@@ -205,10 +204,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
/// </summary>
public IEnumerable<SelectListItem> GetAssociationTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> associationTypes = GetCodesOfType(SystemCode.AssociationType);
associationTypes.Insert(0, AssociationType.Any, "", Localiser["label.any"]);
associationTypes.RemoveAll(item => item.Type == (short)AssociationType.Internal);
foreach (AssociationType associationType in EnumUtil.GetValues<AssociationType>())
List<TypeCodeDesc> associationTypes = GetCodesOfType(Sbm.SystemCode.AssociationType);
associationTypes.Insert(0, Sbm.AssociationType.Any, "", Localiser["label.any"]);
associationTypes.RemoveAll(item => item.Type == (short)Sbm.AssociationType.Internal);
foreach (Sbm.AssociationType associationType in EnumUtil.GetValues<Sbm.AssociationType>())
{
if (!SessionConsole.AllowAssociationType(associationType))
associationTypes.RemoveAll(item => item.Type == (short)associationType);
@@ -225,10 +224,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetCommodityTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
commodityTypes.Add(CommodityType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc commodityType in GetCodesOfType(SystemCode.CommodityType))
commodityTypes.Add(Sbm.CommodityType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(Sbm.ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
@@ -240,9 +239,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetCommodityTypeCodesForDropdown()
{
List<TypeCodeDesc> commodityTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc commodityType in GetCodesOfType(SystemCode.CommodityType))
foreach (TypeCodeDesc commodityType in GetCodesOfType(Sbm.SystemCode.CommodityType))
{
if (commodityType.Type == (int)CommodityType.Asset && !SessionConsole.AllowOption(ConfigOption.Assets)) continue;
if (commodityType.Type == (int)Sbm.CommodityType.Asset && !SessionConsole.AllowOption(Sbm.ConfigOption.Assets)) continue;
commodityTypes.Add(commodityType);
}
return new SelectList(commodityTypes, "Code", "Desc");
@@ -254,8 +253,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetAssetTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> assetTypes = new List<TypeCodeDesc>();
assetTypes.Add(AssetType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc assetType in GetCodesOfType(SystemCode.AssetType))
assetTypes.Add(Sbm.AssetType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc assetType in GetCodesOfType(Sbm.SystemCode.AssetType))
{
assetTypes.Add(assetType);
}
@@ -268,7 +267,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetAssetTypeCodesForDropdown()
{
List<TypeCodeDesc> assetTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc assetType in GetCodesOfType(SystemCode.AssetType))
foreach (TypeCodeDesc assetType in GetCodesOfType(Sbm.SystemCode.AssetType))
{
assetTypes.Add(assetType);
}
@@ -284,11 +283,11 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetTransactionTypeCodesForFilterDropdown()
{
List<TypeCodeDesc> transactionTypes = new List<TypeCodeDesc>();
transactionTypes.Add(TransactionType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc transactionType in GetCodesOfType(SystemCode.TransactionType))
transactionTypes.Add(Sbm.TransactionType.Any, "", Localiser["label.any"]);
foreach (TypeCodeDesc transactionType in GetCodesOfType(Sbm.SystemCode.TransactionType))
{
if (!SessionConsole.AllowTransactionType((TransactionType)transactionType.Type)) continue;
string description = SessionConsole.GetOwnerOption_Caption(TransTypeToOrgOption((TransactionType)transactionType.Type), Localiser.GetTransactionTypeCaption((TransactionType)transactionType.Type));
if (!SessionConsole.AllowTransactionType((Sbm.TransactionType)transactionType.Type)) continue;
string description = SessionConsole.GetOwnerOption_Caption(Sbm.TransTypeToOrgOption((Sbm.TransactionType)transactionType.Type), Localiser.GetTransactionTypeCaption((Sbm.TransactionType)transactionType.Type));
transactionTypes.Add(transactionType.Type, transactionType.Code, description);
}
return new SelectList(transactionTypes, "Code", "Desc");
@@ -300,10 +299,10 @@ namespace Sarand.BusinessMgr.Web.Portal.Components
public IEnumerable<SelectListItem> GetTransactionTypeCodesForDropdown()
{
List<TypeCodeDesc> transactionTypes = new List<TypeCodeDesc>();
foreach (TypeCodeDesc transactionType in GetCodesOfType(SystemCode.TransactionType))
foreach (TypeCodeDesc transactionType in GetCodesOfType(Sbm.SystemCode.TransactionType))
{
if (!SessionConsole.AllowTransactionType((TransactionType)transactionType.Type)) continue;
string description = SessionConsole.GetOwnerOption_Caption(TransTypeToOrgOption((TransactionType)transactionType.Type), Localiser.GetTransactionTypeCaption((TransactionType)transactionType.Type));
if (!SessionConsole.AllowTransactionType((Sbm.TransactionType)transactionType.Type)) continue;
string description = SessionConsole.GetOwnerOption_Caption(Sbm.TransTypeToOrgOption((Sbm.TransactionType)transactionType.Type), Localiser.GetTransactionTypeCaption((Sbm.TransactionType)transactionType.Type));
transactionTypes.Add(transactionType.Type, transactionType.Code, description);
}
return new SelectList(transactionTypes, "Code", "Desc");
@@ -0,0 +1,378 @@
using Microsoft.Extensions.Logging.Abstractions;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Core;
using Sarand.BusinessMgr.Net.Standard.Base.Data;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
namespace Sarand.BusinessMgr.Web.Portal.Consoles
{
//=======================================================================
public class SbmDemoInstanceConsole_Portal : SbmDemoInstanceConsole
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private class DataMembers
{
public DataMembers(SbmSessionContext sessionContext)
{
this.SessionContext = sessionContext;
SessionData = new SbmSessionData_Portal(sessionContext);
}
public SbmSessionContext SessionContext { get; }
public SbmSessionData_Portal SessionData { get; }
public SbmInternals Internals { get; set; }
public SbmCoreInstanceConsole InstanceConsole { get; set; }
}
private DataMembers mbr { get; }
//-------------------------------------------------------------------
// Construction.
public SbmDemoInstanceConsole_Portal(SbmSessionContext sessionContext)
{
mbr = new DataMembers(sessionContext);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (mbr.Internals != null) mbr.Internals.Dispose();
if (mbr.InstanceConsole != null) mbr.InstanceConsole.Dispose();
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
protected override SbmInternals Internals { get { if (mbr.Internals == null) { mbr.Internals = new SbmInternals(mbr.SessionData); } return mbr.Internals; } }
protected override SbmCoreInstanceConsole InstanceConsole { get { if (mbr.InstanceConsole == null) { mbr.InstanceConsole = new SbmCoreInstanceConsole_Portal(mbr.SessionContext); } return mbr.InstanceConsole; } }
//-------------------------------------------------------------------
// Utilities.
//-------------------------------------------------------------------
// Repository population data preparation.
/// <summary>
/// Prepare a suitable batch of data to populate the demo database.
/// <br/>- Randomly crafted.
/// <br/>- Selected from data stored on the Control database.
/// </summary>
public override SbmRepositoryPopulationData PrepareDemoPopulationData()
{
SbmRepositoryPopulationData data = new SbmRepositoryPopulationData();
// Owner.
data.InitData.Organisation.Name = "Board Game Outlet";
data.InitData.Organisation.Website = "http://www.boardgameoutlet.co.uk/";
data.InitData.User.FirstName = "Awesome";
data.InitData.User.LastName = "Player";
data.InitData.User.Email = "ap@www.boardgameoutlet.co.uk";
data.InitData.User.Code = data.InitData.User.Email;
data.InitData.User.Password = "ap@www.boardgameoutlet.co.uk";
// Contacts - Organisations.
SbmRepositoryPopulationData.OrganisationData organisation01 = new SbmRepositoryPopulationData.CommercialOrganisationData() { Name = "Online Board Games" };
organisation01.SetCustomer("CUST123");
SbmRepositoryPopulationData.OrganisationData organisation02 = new SbmRepositoryPopulationData.CommercialOrganisationData() { Name = "Traditional Pastimes Ltd" };
organisation02.SetCustomer("CUST017");
SbmRepositoryPopulationData.OrganisationData organisation03 = new SbmRepositoryPopulationData.CommercialOrganisationData() { Name = "Surplus Stock Ltd" };
organisation02.SetSupplier("SUPP012");
SbmRepositoryPopulationData.OrganisationData organisation04 = new SbmRepositoryPopulationData.CharityOrganisationData() { Name = "Ethical Game Redistribution" };
organisation04.SetCustomer("CUST1234");
organisation04.SetSupplier("SUPP018");
data.Organisations.AddRange(new List<SbmRepositoryPopulationData.OrganisationData>() { organisation01, organisation02, organisation03, organisation04 });
// Contact - Individuals.
SbmRepositoryPopulationData.IndividualData individual01 = new SbmRepositoryPopulationData.IndividualData() { FirstName = "Billy", LastName = "Sparks", Email = "bs@www.boardgameoutlet.co.uk" };
individual01.SetMember("OBG110", "Dice Cleaner");
SbmRepositoryPopulationData.IndividualData individual02 = new SbmRepositoryPopulationData.IndividualData() { FirstName = "Sally", LastName = "Sparks", Email = "ss@www.boardgameoutlet.co.uk" };
individual02.SetMember("OBG120", "Banker");
data.Individuals.AddRange(new List<SbmRepositoryPopulationData.IndividualData>() { individual01, individual02 });
// Commodities.
SbmRepositoryPopulationData.CommodityData commodity01 = new SbmRepositoryPopulationData.StockCommodityData() { Code = "MONOPOLY-STD", Caption = "Monopoly", SalePrice = 24.75m };
SbmRepositoryPopulationData.CommodityData commodity02 = new SbmRepositoryPopulationData.StockCommodityData() { Code = "MONOPOLY-DEL", Caption = "Monopoly Deluxe", SalePrice = 32.45m };
SbmRepositoryPopulationData.CommodityData commodity03 = new SbmRepositoryPopulationData.StockCommodityData() { Code = "CLUEDO-STD", Caption = "Cluedo", SalePrice = 18.25m };
SbmRepositoryPopulationData.CommodityData commodity04 = new SbmRepositoryPopulationData.StockCommodityData() { Code = "RISK-STD", Caption = "Risk", SalePrice = 21.50m };
data.Commodities.AddRange(new List<SbmRepositoryPopulationData.CommodityData>() { commodity01, commodity02, commodity03, commodity04 });
return data;
}
//-------------------------------------------------------------------
// Populate Repository.
/// <summary>
/// Populate repository.
/// <br/>- Initialise repository: Organisation contact, Internal association, Security item and 'Super' group, User contact, User member association.
/// <br/>- Demo specific security.
/// <br/>- Populate demo data, including Repository configuration.
/// </summary>
public override bool PopulateRepository(SbmRepositoryPopulationData data)
{
ClearErrorState();
if (InstanceConsole.IsRepositoryInitialised())
return true;
// Populate initialisation data.
InstanceConsole.InitialiseRepository(data.InitData);
if (InstanceConsole.HasErrorState())
return SetErrorState(InstanceConsole.ErrorStateMessage);
// Retrieve the initialised business objects to refresh the session data.
// This ensures that remaining data population is done in the context of the initial user account.
SbmAffiliate affiliateOrganisation = Internals.AccountMgr.GetAffiliateById(data.InitData.Organisation.AffiliateId);
SbmAssociation associationInternal = Internals.AccountMgr.GetAssociationById(data.InitData.Organisation.AssociationId);
SbmAffiliate affiliateUser = Internals.AccountMgr.GetAffiliateById(data.InitData.User.AffiliateId);
SaSecurityItem securityItemUser = Internals.SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, data.InitData.User.SecurityItemId);
if (affiliateOrganisation == null || associationInternal == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Organisation Affiliate [{data.InitData.Organisation.AffiliateId}] and Internal Association [{data.InitData.Organisation.AssociationId}].");
return SetErrorState($"Repository initialisation failed (Organisation).");
}
if (affiliateUser == null || securityItemUser == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve User Affiliate [{data.InitData.User.AffiliateId}] and Security Item [{data.InitData.User.SecurityItemId}].");
return SetErrorState($"Repository initialisation failed (User).");
}
mbr.SessionData.Refresh(securityItemUser, affiliateUser, associationInternal, affiliateOrganisation);
// Configure Demo Security components.
if (!ConfigureSecurityComponents()) return false;
// Populate demo data.
if (!PopulateCommodities(data)) return false;
if (!PopulateContacts(data)) return false;
return OK;
}
//-------------------------------------------------------------------
private bool ConfigureSecurityComponents()
{
if (!AddDemoSecurityGroups())
return false;
return OK;
}
private bool AddDemoSecurityGroups()
{
// Registered rights.
List<SaSecurityRight> securityRights = Internals.SecurityConsole.GetRegisteredRights();
HashSet<Sbm.SecurityRight> adminRights = new HashSet<Sbm.SecurityRight>()
{
Sbm.SecurityRight.Security_Admin, Sbm.SecurityRight.Database_Admin, Sbm.SecurityRight.ReferenceData_Admin,
Sbm.SecurityRight.InterfaceConfig, Sbm.SecurityRight.TimesheetManager, Sbm.SecurityRight.TaskManager
};
// 'Standard' security group.
List<SaSecurityRight> securityRights_Standard = securityRights.Where(right => !adminRights.Contains((Sbm.SecurityRight)right.Type)).ToList();
if (!AddSecurityGroup(GetSecurityGroupCode(ISbmDemoInstanceConsole.SecurityGroup.Standard), "Standard", securityRights_Standard))
return false;
return OK;
}
private bool AddSecurityGroup(String groupCode, String groupCaption, List<SaSecurityRight> rights)
{
ClearErrorState();
SaSecurityItem securityGroup = Internals.SecurityConsole.GetSecurityItemByCode(SaSecurity.ItemType.Group, groupCode);
if (securityGroup == null)
{
if (!Internals.SecurityConsole.CreateGroup(groupCode, groupCaption, DbUpdateInfo))
return SetErrorState($"Failed to create Standard Security Group - {Internals.SecurityConsole.ErrorStateMessage.TrimEnd('.')}.");
}
securityGroup = Internals.SecurityConsole.GetSecurityItemByCode(SaSecurity.ItemType.Group, groupCode);
if (securityGroup == null)
return SetErrorState($"Failed to retrieve Standard Security Group.");
if (securityGroup != null)
{
// Create a link with each right in the list.
SaSecurityItem.Params prmSecItem = new SaSecurityItem.Params();
prmSecItem.SecurityItemType = SaSecurity.ItemType.Right;
foreach (SaSecurityItem securityRight in Internals.SecurityConsole.GetSecurityItemList(prmSecItem))
{
// Exclude rights not in the supplied list.
if (!rights.Any(right => right.Code.EqualsCI(securityRight.Code))) continue;
// Exclude right that are associated with a Data Item.
if (securityRight.DataItemType > 0) continue;
// Assign right to the Security Group.
if (!Internals.SecurityConsole.AssignRightToGroup(securityRight.Code, securityGroup.Code, DbUpdateInfo))
return SetErrorState(Internals.SecurityConsole.ErrorStateMessage);
}
}
return OK;
}
//-------------------------------------------------------------------
// Populate demo commodities.
private bool PopulateCommodities(SbmRepositoryPopulationData data)
{
if (HasErrorState()) return false;
SysId affilliateIdOwner = data.AffiliateIdOrganisation;
foreach (var commodityData in data.Commodities)
{
SbmCommodity commodity = Internals.CommodityMgr.CreateCommodity(commodityData.Type, commodityData.Code);
commodity.DescBrief = commodityData.Caption;
commodity.SalesPrice = commodityData.SalePrice;
if (!Internals.CommodityMgr.InsertCommodity(commodity, DbUpdateInfo))
{
string msg = "Repository population failed (Commodity).";
SaLogger.Warn($"{SysUtil.Fn} {msg} {Internals.CommodityMgr.ErrorStateMessage.TrimEnd('.')}.");
return SetErrorState($"{msg}");
}
}
return OK;
}
//-------------------------------------------------------------------
// Populate demo contacts.
private bool PopulateContacts(SbmRepositoryPopulationData data)
{
if (HasErrorState()) return false;
if (!SysId.IsValid(data.AffiliateIdOrganisation))
{
string msg = "Repository population failed (Owner Id).";
SaLogger.Warn($"{SysUtil.Fn} {msg}");
return SetErrorState($"{msg}");
}
// Organisations.
foreach (var organisation in data.Organisations)
{
SbmAffiliate affiliate = Internals.AccountMgr.CreateAffiliate(organisation.Type);
affiliate.Name = organisation.Name;
affiliate.Abbr = organisation.Abbr;
affiliate.Nature = organisation.Nature;
affiliate.Contact = organisation.Contact;
affiliate.PhoneMain = organisation.PhoneMain;
affiliate.PhoneAlt = organisation.PhoneAlt;
affiliate.CompanyNo = organisation.CompanyNo;
affiliate.VatReg = organisation.VatReg;
affiliate.Website = organisation.Website;
if (Internals.AccountMgr.InsertAffiliate(affiliate, DbUpdateInfo))
{
if (!PopulateAffiliate(data.AffiliateIdOrganisation, affiliate, organisation))
return false;
}
else
{
string msg = "Repository population failed (Individual).";
SaLogger.Warn($"{SysUtil.Fn} {msg} {Internals.AccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return SetErrorState($"{msg}");
}
}
// Individuals.
foreach (var individual in data.Individuals)
{
SbmAffiliate affiliate = Internals.AccountMgr.CreateAffiliate(individual.Type);
affiliate.FirstName = individual.FirstName;
affiliate.LastName = individual.LastName;
affiliate.Email = individual.Email;
affiliate.PhoneMain = individual.PhoneMain;
affiliate.PhoneMobile = individual.PhoneMobile;
if (Internals.AccountMgr.InsertAffiliate(affiliate, DbUpdateInfo))
{
if (!PopulateAffiliate(data.AffiliateIdOrganisation, affiliate, individual))
return false;
}
else
{
string msg = "Repository population failed (Individual).";
SaLogger.Warn($"{SysUtil.Fn} {msg} {Internals.AccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return SetErrorState($"{msg}");
}
}
return OK;
}
// Populate Affiliate.
private bool PopulateAffiliate(SysId affilliateIdOwner, SbmAffiliate affiliate, SbmRepositoryPopulationData.AffiliateData affiliateData)
{
if (HasErrorState()) return false;
foreach (var addressData in affiliateData.Addresses)
{
SbmAddress address = Internals.AccountMgr.CreateAddress(Sbm.ItemType.Affiliate, affiliate.Id, addressData.Type);
address.Line1 = address.Line1;
address.Line2 = address.Line2;
address.Line3 = address.Line3;
address.City = address.City;
address.Province = address.Province;
address.Postcode = address.Postcode;
address.Country = address.Country;
if (!Internals.AccountMgr.InsertAddress(address, DbUpdateInfo))
{
string msg = "Repository population failed (Address).";
SaLogger.Warn($"{SysUtil.Fn} {msg} {Internals.AccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return SetErrorState($"{msg}");
}
}
// Associations.
if (!PopulateAssociation(affilliateIdOwner, affiliate, affiliateData.Customer))
{
string msg = "Repository population failed (Customer).";
SaLogger.Warn($"{SysUtil.Fn} {msg}");
return SetErrorState($"{msg}");
}
if (!PopulateAssociation(affilliateIdOwner, affiliate, affiliateData.Supplier))
{
string msg = "Repository population failed (Supplier).";
SaLogger.Warn($"{SysUtil.Fn} {msg}");
return SetErrorState($"{msg}");
}
if (!PopulateAssociation(affilliateIdOwner, affiliate, affiliateData.Member))
{
string msg = "Repository population failed (Member).";
SaLogger.Warn($"{SysUtil.Fn} {msg}");
return SetErrorState($"{msg}");
}
return OK;
}
// Populate Association.
private bool PopulateAssociation(SysId affilliateIdOwner, SbmAffiliate affiliate, SbmRepositoryPopulationData.AssociationData associationData)
{
if (HasErrorState()) return false;
if (associationData == null) return true;
SbmAssociation association = Internals.AccountMgr.CreateAssociation(affilliateIdOwner, associationData.Type, affiliate.Id);
association.Code = associationData.Code;
association.Location = associationData.Location;
association.Role = associationData.Role;
association.PhoneMain = associationData.PhoneMain;
if (Internals.AccountMgr.InsertAssociation(association, DbUpdateInfo))
{
// ToDo Populate Transactions.
}
else
{
string msg = $"Repository population failed ({associationData.Type}).";
SaLogger.Warn($"{SysUtil.Fn} {msg} {Internals.AccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return SetErrorState($"{msg}");
}
return OK;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -14,8 +14,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Consoles
//-------------------------------------------------------------------
// Construction.
public SbmReferenceDataConsole_Portal(ISbmUserOrganisationContext userContext) :
base(userContext)
public SbmReferenceDataConsole_Portal(SbmInternals internals) :
base(internals)
{
}
protected override void Dispose(bool disposing)
@@ -3,7 +3,6 @@ using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Models.Assets;
using Sarand.BusinessMgr.Web.Portal.Models.Commodities;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -11,7 +10,6 @@ using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
{
@@ -28,7 +26,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
public String Code { get; set; }
public String Caption { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private class AssetCategoryItemData : AssetCategoryListData
{
@@ -1,7 +1,6 @@
using Microsoft.AspNetCore.Mvc;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Models.Assets;
using Sarand.Net.Standard.Base.App;
@@ -11,9 +10,6 @@ using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
using static Sarand.BusinessMgr.Net.Standard.Base.App.Sbm;
using static Sarand.BusinessMgr.Web.Portal.Models.Assets.Model_AssetCategory;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
{
@@ -29,7 +25,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Assets
public String CategoryDesc { get; set; }
public String Caption { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private class AssetItemData : AssetListData
{
@@ -12,7 +12,6 @@ using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
{
@@ -29,7 +28,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
public String Code { get; set; }
public String Caption { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private enum CommodityDataGroup
{
@@ -19,6 +19,8 @@ using Sarand.BusinessMgr.Web.Portal.Components;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Commodities
{
//=======================================================================
// Portal Commodity Controller.
//=======================================================================
public partial class CommodityController : SbmController_Portal
{
@@ -13,7 +13,6 @@ using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
{
@@ -32,7 +31,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
// Address.
public String AddressSummary { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private class AssociationItemData : AssociationListData
{
@@ -15,7 +15,6 @@ using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
{
@@ -33,7 +32,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
// Affiliate properties for list with specific handling.
public long? AssociationCount { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private class AffiliateItemData : AffiliateListData
{
@@ -44,6 +43,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
private void PopulateAffiliateResponseListData(Model_Contact model, SbmAffiliate affiliate, AffiliateListData data)
{
data.Id = SysId.ToString(affiliate.Id);
data.AssociationCount = AccountMgr.GetAffiliateTargetAssociationCount(affiliate.Id, Sbm.AssociationType.NotInternal);
}
private void PopulateAffiliateResponseItemData(Model_Contact model, SbmAffiliate affiliate, AffiliateItemData data)
{
@@ -230,7 +230,6 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
ColumnDfn colPhoneMobile = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneMobile);
ColumnDfn colPhoneDirect = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneDirect);
ColumnDfn colEmail = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Email);
ColumnDfn colAssocOwnerCount = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.AssociationOwner_Count);
ColumnDfn colAssocTargetCount = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.AssociationTarget_Count);
ColumnDfn colNotes = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Notes);
ColumnDfn colStatus = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Status);
@@ -239,7 +238,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId, colName, colAffiliateType,
colAddress, colContact, colPhoneMain, colPhoneAlt, colPhoneMobile, colPhoneDirect, colEmail, colAssocOwnerCount, colAssocTargetCount,
colAddress, colContact, colPhoneMain, colPhoneAlt, colPhoneMobile, colPhoneDirect, colEmail, colAssocTargetCount,
colNotes, colStatus, colCreatedOn, colUpdatedOn
};
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Address}"))
@@ -247,7 +246,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Contacts
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Email}"))
columns.Remove(colEmail);
if (responseData.Config.Column.Hide.Contains($"{Model_Contact.ItemField.Associations}"))
columns.Remove(colAssocOwnerCount);
columns.Remove(colAssocTargetCount);
// Sort Columns.
if (!prmAffiliate.SortColumns.Any())
@@ -276,9 +275,7 @@ 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.CreatedOn}", Localiser.FormatDate(values.GetDate(colCreatedOn.DataName)));
affiliateData.Field.Value.Add($"{Model_Contact.ItemField.UpdatedOn}", Localiser.FormatDate(values.GetDate(colUpdatedOn.DataName)));
long assocOwnerCount = values.GetLong(colAssocOwnerCount.DataName);
long assocTargetCount = values.GetLong(colAssocTargetCount.DataName);
long assocCount = assocOwnerCount + assocTargetCount;
long assocCount = values.GetLong(colAssocTargetCount.DataName);
if (assocCount > 0)
affiliateData.AssociationCount = assocCount;
// Cleanse item values.
@@ -0,0 +1,339 @@
using Microsoft.AspNetCore.Mvc;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Data;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.BusinessMgr.Web.Portal.Models.Security;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Email;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using static Sarand.BusinessMgr.Net.Standard.Base.Data.SbmRepositoryPopulationData;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Home
{
//=======================================================================
// Portal Demo Controller - Ajax Actions.
//=======================================================================
partial class DemoController
{
//-------------------------------------------------------------------
// Demo Account Request.
//-------------------------------------------------------------------
private class AjaxResponse_DemoAccountRequest : AjaxResponse_Data
{
// Construction.
public AjaxResponse_DemoAccountRequest(Model_Demo model) : base(model) { }
}
// Ajax request.
[HttpPost]
[Route("Demo/Ajax/Request")]
public IActionResult Ajax_DemoAccountRequest(Model_Demo model)
{
AjaxResponse_DemoAccountRequest responseData = new AjaxResponse_DemoAccountRequest(model);
String messageTitle = Localiser["caption.request.demo.account"];
// Validate session and referrer.
if (ValidUserSession) return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
RefreshModel(model);
// Validate item properties.
model.ValidateRequestData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Retrieve existing incomplete Account Request.
SbmcAccountRegistration accountRegistration = ControlAccountMgr.GetAccountRegistrationByEmailStatus(model.EmailAddress, SbmcAccountRegistration.StatusCat.AwaitingOnly);
if (accountRegistration == null)
{
accountRegistration = ControlAccountMgr.CreateAccountRegistration(model.EmailAddress, Guid.NewGuid());
if (!ControlAccountMgr.InsertAccountRegistration(accountRegistration, new DbUpdateInfo(null, "Registration", SacsSystem.ComputerName)))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to insert Account Registration - {ControlAccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
}
else
{
// Reset requested time on existing registration.
accountRegistration.RequestAccountAt = DateTime.Now;
if (!ControlAccountMgr.UpdateAccountRegistration(accountRegistration, new DbUpdateInfo(null, "Registration", SacsSystem.ComputerName)))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to update Account Registration - {ControlAccountMgr.ErrorStateMessage.TrimEnd('.')}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
}
// Construct email.
SbmEmailConsole emailConsole = SbmApplication_Portal.Instance.CreateEmailConsole();
// Demo Account Registration email.
SaEmailData emailData = new SaEmailData();
emailData.Config = App.EmailConfig;
emailData.AddressesTo.Add(model.EmailAddress);
emailData.Subject = $"BusinessMgr - {Localiser["caption.register.demo.account"]}";
emailData.MessageBody = SbmResourceHelper.GetResourceText(SbmResourceHelper.TextResource.Email_DemoAccountRequest_Html);
emailData.HtmlBody = true;
emailConsole.ReplaceDynamicEmailBodyTags(emailData, null);
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.DemoAccountRegister]", GenerateRegisterDemoAccountLink(model.EmailAddress, accountRegistration.RegisterAccountToken));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", GetRegisterDemoAccountLinkExpiresMinutes().ToString());
if (emailConsole.SendEmail(emailData))
SaLogger.Info($"{SysUtil.Fn} Demo Account Registration email sent to {model.EmailAddress}.", true);
else
{
SaLogger.Warn($"{SysUtil.Fn} Failed to send Demo Account Registration email to {model.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, "Unfortunately it has not been possible to send your Demo Account Registration email. Please try again at a later time."));
}
// Complete response.
responseData.Success = true;
return Json(responseData.SetConfirmMessage(messageTitle, "Demo Account Registration link has been sent to your email account.\n\nUse the link in this email to complete your registration details."));
}
//-------------------------------------------------------------------
// Demo Account Register.
//-------------------------------------------------------------------
private class AjaxResponse_DemoAccountRegister : AjaxResponse_Data
{
// Construction.
public AjaxResponse_DemoAccountRegister(Model_Demo model) : base(model) { }
}
// Ajax register.
[HttpPost]
[Route("Demo/Ajax/Register")]
public IActionResult Ajax_DemoAccountRegister(Model_Demo model)
{
AjaxResponse_DemoAccountRegister responseData = new AjaxResponse_DemoAccountRegister(model);
String messageTitle = Localiser["caption.register.demo.account"];
// Validate session and referrer.
if (ValidUserSession) return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
RefreshModel(model);
// Validate item properties.
model.ValidateRegisterData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
using (DisposableCollection<SacsDisposable> disposables = new DisposableCollection<SacsDisposable>())
{
//---------------------------------------------------------------
// Extract Request Parameters.
RegisterDemoAccountParams requestParams = ExtractRegisterDemoAccountParams(model.RequestParams);
if (!requestParams.IsValid())
{
SaLogger.Warn($"{SysUtil.Fn} Incomplete Account Registration Request parameters.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Verify Demo Account Registration Params Email.
if (!requestParams.EmailAddress.EqualsCI(model.EmailAddress))
{
SaLogger.Warn($"{SysUtil.Fn} Invalid Account Registration parameters email. Expected: {model.EmailAddress}. Found: {requestParams.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
//---------------------------------------------------------------
// Retrieve Account Registration by token.
SbmcAccountRegistration accountRegistration = ControlAccountMgr.GetAccountRegistrationByRegisterAccountToken(requestParams.Token);
if (accountRegistration == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Account Registration for token - {requestParams.Token}. Email: {model.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Verify Account Registration Email.
if (!accountRegistration.EmailAddress.EqualsCI(model.EmailAddress))
{
SaLogger.Warn($"{SysUtil.Fn} Invalid Account Registration email. Expected: {model.EmailAddress}. Found: {accountRegistration.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Verify Password.
if (!SbmPasswordHelper.IsValidPassword(model.Password))
{
SaLogger.Warn($"{SysUtil.Fn} Invalid Password. Email: {model.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
//---------------------------------------------------------------
// Initialise repository if needed.
SbmDemoInstanceConsole demoInstanceConsole = SbmApplication_Portal.Instance.CreateDemoInstanceConsole();
disposables.Add(demoInstanceConsole);
if (!demoInstanceConsole.IsRepositoryValid())
{
SaLogger.Warn($"{SysUtil.Fn} Demo Instance is not valid. {demoInstanceConsole.ErrorStateMessage.TrimEnd('.')}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
SbmRepositoryPopulationData demoData = demoInstanceConsole.PrepareDemoPopulationData();
if (!demoInstanceConsole.PopulateRepository(demoData))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to populate Demo instance. {demoInstanceConsole.ErrorStateMessage.TrimEnd('.')}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Create User Account.
SbmRepositoryPopulationData.UserAccount userAccount = new UserAccount()
{
AffiliateIdOwner = demoData.AffiliateIdOrganisation,
FirstName = model.FirstName,
LastName = model.LastName,
Email = model.EmailAddress,
MemberCode = "",
UserCode = model.EmailAddress,
Password = model.Password,
SecurityGroupCode = demoInstanceConsole.GetSecurityGroupCode(Net.Standard.Base.Core.ISbmDemoInstanceConsole.SecurityGroup.Standard)
};
if (!SysId.IsValid(userAccount.AffiliateIdOwner))
{
// Owner Affiliate Id not populated as Demo Repository previously initlialised.
// Populate with the first Internal Association Affiliate Id in the data.
userAccount.AffiliateIdOwner = demoInstanceConsole.GetInternalAssociationAffiliateIdsOwner().FirstOrDefault();
}
if (!SysId.IsValid(userAccount.AffiliateIdOwner))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to add User Account. Unable to identify Internal Association Owner.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (!demoInstanceConsole.AddUserAccount(userAccount))
{
SaLogger.Warn($"{SysUtil.Fn} Failed to add User Account. {demoInstanceConsole.ErrorStateMessage.TrimEnd('.')}.");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
//---------------------------------------------------------------
// Construct email.
SbmEmailConsole emailConsole = SbmApplication_Portal.Instance.CreateEmailConsole();
// Demo Account Registration email.
SaEmailData emailData = new SaEmailData();
emailData.Config = App.EmailConfig;
emailData.AddressesTo.Add(model.EmailAddress);
emailData.Subject = $"BusinessMgr - {Localiser["caption.register.demo.account"]}";
emailData.MessageBody = SbmResourceHelper.GetResourceText(SbmResourceHelper.TextResource.Email_DemoAccountRegister_Html);
emailData.HtmlBody = true;
emailConsole.ReplaceDynamicEmailBodyTags(emailData, null);
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.DemoAccountSignin]", $"{GetRedirectLocation(RedirectLocation.WebAppBase)}Security/Signin/{Sbm.RepositoryContext_Demo}/{model.EmailAddress}");
if (emailConsole.SendEmail(emailData))
SaLogger.Info($"{SysUtil.Fn} Demo Account Registration email sent to {model.EmailAddress}.", true);
else
{
SaLogger.Warn($"{SysUtil.Fn} Failed to send Demo Account Registration email to {model.EmailAddress}.");
return Json(responseData.SetMessage(messageTitle, "Unfortunately it has not been possible to send your Demo Account Registration email. Please try again at a later time."));
}
}
// Complete response.
responseData.Success = true;
return Json(responseData.SetConfirmMessage(messageTitle, "Thank you for registering to access the Demo data.\n\nYou will receive an email with a link to Signin to the system.\n\nAlternatively, use the Signin option at the top of the page and enter 'Demo' as the Context."));
}
//-------------------------------------------------------------------
// Demo Account Registration link.
// Portal Demo Account Registration encryption parameters (key & IV).
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
// IV Must be regenerated if key is changed.
protected static string Base64Key_RegisterDemoAccount_Portal { get; } = SacsEncryptionHelper.EncodePlainKey("<s58usin3S5m6R#Register@Demo~Account]", SacsEncryptionHelper.KeyLength);
//private static String Base64IV_RegisterDemoAccount_Generated_Portal = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RegisterDemoAccount_Portal);
protected static string Base64IV_RegisterDemoAccount_Portal { get; } = "0PWPChEJgMzjiZ2yM8E2Kw==";
// Link parameters.
private static String ParamName_RegisterDemoAccountEncrypted { get; } = "rda";
private static String ParamName_EmailAddress { get; } = "ema";
private static String ParamName_ExpiresAt { get; } = "exp";
private static String ParamName_Token { get; } = "tok";
private String GenerateRegisterDemoAccountLink(String emailAddress, Guid registerDemoAccountToken)
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add(ParamName_EmailAddress, emailAddress);
parameters.Add(ParamName_ExpiresAt, DateUtil.Format(DateTime.Now.AddMinutes(GetRegisterDemoAccountLinkExpiresMinutes()), DateUtil.Format_XmlDateTime));
parameters.Add(ParamName_Token, registerDemoAccountToken.ToString());
String link =
$"{GetRedirectLocation(RedirectLocation.WebAppBase)}Demo/Register?" +
$"{ParamName_RegisterDemoAccountEncrypted}={HttpUtility.UrlEncode(EncryptParameters(parameters, Base64IV_RegisterDemoAccount_Portal, Base64Key_RegisterDemoAccount_Portal))}";
return link;
}
private int GetRegisterDemoAccountLinkExpiresMinutes()
{
int expiresMinutes = AppConfig.Security.Demo.Account.Register.EmailLinkExpiresMins;
int expiresMinutes_Min = Sbm.Config.Security.Demo.Register.EmailLinkExpiresMins_Min;
int expiresMinutes_Max = Sbm.Config.Security.Demo.Register.EmailLinkExpiresMins_Max;
return Math.Max(expiresMinutes_Min, Math.Min(expiresMinutes_Max, expiresMinutes));
}
private class RegisterDemoAccountParams
{
public String EmailAddress { get; set; }
public DateTime ExpiresAt { get; set; }
public Guid Token { get; set; }
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
public List<String> GetValidParams()
{
List<String> values = new List<String>();
if (!StringUtil.IsBlank(EmailAddress))
values.Add($"Email: {EmailAddress}");
if (DateUtil.IsValid(ExpiresAt))
values.Add($"Expires: {DateUtil.FormatXmlDateTime(ExpiresAt)}");
if (Token != Guid.Empty)
values.Add($"Token: {Token}");
return values;
}
public bool IsExpired()
{
return !DateUtil.IsValid(ExpiresAt) || ExpiresAt < DateTime.Now;
}
/// <summary>Verifiy that the email and account Ids are populated and the data hasn't expired.</summary>
public bool IsValid()
{
return !StringUtil.IsBlank(EmailAddress) && Token != Guid.Empty && !IsExpired();
}
/// <summary>Verify that the data is valid and the account details match.</summary>
public bool IsValid(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser)
{
return
IsValid() &&
securityItemUser.EmailAddress.EqualsCI(EmailAddress);
}
}
private RegisterDemoAccountParams ExtractRegisterDemoAccountParams(String encryptedParams)
{
RegisterDemoAccountParams registerDemoAccountParams = new RegisterDemoAccountParams();
if (!StringUtil.IsEmpty(encryptedParams))
{
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RegisterDemoAccount_Portal, Base64Key_RegisterDemoAccount_Portal);
registerDemoAccountParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
registerDemoAccountParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
if (!StringUtil.IsBlank(linkParams.Get(ParamName_Token)))
{
try
{
registerDemoAccountParams.Token = new Guid(linkParams.Get(ParamName_Token));
}
catch (Exception exc)
{
SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, $"extracting Guid from '{linkParams.Get(ParamName_Token)}'")}");
}
}
}
return registerDemoAccountParams;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,103 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Models.Home;
using Sarand.BusinessMgr.Web.Portal.Models.Security;
using DocumentFormat.OpenXml.EMMA;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Home
{
//=======================================================================
// Portal Demo Controller.
//=======================================================================
public partial class DemoController : SbmController_Portal
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public DemoController(SbmLocaliser localiser, ILogger<DemoController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
[HttpGet]
[Route("Demo/Request")]
public IActionResult DemoRequest()
{
// Redirect to home page if user signed-in.
if (ValidUserSession)
{
return RedirectToAction("", "Home");
}
// Demo User Request page.
Model_Demo model = new Model_Demo(Localiser);
model.RegisterDemoAccountLinkExpiresMinutes = GetRegisterDemoAccountLinkExpiresMinutes();
return View("Views/Home/Demo/Request.cshtml", model);
}
//-------------------------------------------------------------------
[HttpGet]
[Route("Demo/Register")]
public IActionResult DemoRegister(String rda)
{
// Redirect to home page if user signed-in or no parameters supplied.
if (ValidUserSession || StringUtil.IsEmpty(rda))
{
return RedirectToAction("", "Home");
}
// Demo Account model.
Model_Demo model = new Model_Demo(Localiser);
String registerView = "Views/Home/Demo/Register.cshtml";
// Extract Request Parameters.
RegisterDemoAccountParams registerParams = ExtractRegisterDemoAccountParams(rda);
if (!registerParams.IsValid())
{
if (StringUtil.IsEmpty(registerParams.EmailAddress) || registerParams.Token == Guid.Empty)
{
SaLogger.Warn($"{SysUtil.Fn} Incomplete Account Registration Request parameters.");
model.DemoAccountRegistrationMessage = "Your registration parameters are incomplete.\n\nPlease request another email for Demo Account Registration.";
return View(registerView, model);
}
if (DateUtil.IsValid(registerParams.ExpiresAt) && registerParams.ExpiresAt < DateTime.Now)
{
SaLogger.Warn($"{SysUtil.Fn} Account Registration Request parameters have expired.");
model.DemoAccountRegistrationMessage = "Your registration parameters have expired.\n\nPlease request another email for Demo Account Registration.";
return View(registerView, model);
}
// Default response for invalid parameters - redirect to Home page.
SaLogger.Warn($"{SysUtil.Fn} Invalid Account Registration Request parameters.");
return RedirectToAction("", "Home");
}
model.EmailAddress = registerParams.EmailAddress;
model.RequestParams = rda;
model.DemoAccountRegistrationValid = true;
// Demo User Registration page.
return View(registerView, model);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,71 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Models.Home;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Home
{
//=======================================================================
// Portal Home Controller.
//=======================================================================
public class HomeController : SbmController_Portal
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public HomeController(SbmLocaliser localiser, ILogger<HomeController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
[HttpGet]
[Route("Home")]
[Route("")]
public IActionResult Index()
{
if (!ValidUserSession)
AutoLoginUser();
// Redirect to sign-in if not signed-in.
if (!ValidUserSession)
{
ClearKeepLoggedInCookie();
//return RedirectToAction("", "Security");
}
// Home page.
Model_Home model = new Model_Home(Localiser);
model.ProhibitCache = false;
return View(model);
}
//-------------------------------------------------------------------
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
[Route("Error")]
public IActionResult Error()
{
return View(new ErrorViewModel(Localiser) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -1,65 +0,0 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Sarand.BusinessMgr.Web.Portal.Components;
namespace Sarand.BusinessMgr.Web.Portal.Controllers
{
//=======================================================================
public class HomeController : SbmController_Portal
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public HomeController(SbmLocaliser localiser, ILogger<HomeController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
[HttpGet]
public IActionResult Index()
{
if (!ValidUserSession)
AutoLoginUser();
// Redirect to sign-in if not signed-in.
if (!ValidUserSession)
{
ClearKeepLoggedInCookie();
return RedirectToAction("", "Security");
}
// Home page.
Model_Home model = new Model_Home(Localiser);
model.ProhibitCache = false;
return View(model);
}
//-------------------------------------------------------------------
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel(Localiser) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -8,7 +8,7 @@ using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Helpers;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Web.Portal.Models.Security;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -58,7 +58,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (!(SessionData_Portal?.ValidUser ?? false))
{
// Instance Repository configured on Control database.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext);
SbmSessionContext sessionContext = SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(model.RepositoryContext);
String errorMessage = "";
if (!OpenUserSession(model, sessionContext, ref errorMessage))
{
@@ -116,8 +116,11 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
return false;
}
// Populate User properties to the Session Data.
sessionDataForUser.Refresh(securityItemUser, affiliateUser, null, null);
// User's organisation association.
SbmAssociation associationOrganisation = GetOrganisationAssociationForSignIn(internalsForUser.AccountMgr, model, sessionDataForUser);
SbmAssociation associationOrganisation = GetOrganisationAssociationForSignIn(internalsForUser, model, sessionDataForUser);
disposables.Add(associationOrganisation);
if (associationOrganisation == null)
{
@@ -134,7 +137,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
return false;
}
// Populate User properties to the Session Data.
// Populate User and Organisation properties to the Session Data.
sessionDataForUser.Refresh(securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation);
// Initialise user session.
@@ -156,7 +159,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
}
// Validate password.
if (!SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password) && !(DebugMode && model.EmailAddress.EqualsCI("andy@sarand.com")))
if (!securityConsoleForUser.PasswordMatches(securityItemUser, model.Password, userContext.DbUpdateInfo) && !(DebugMode && model.EmailAddress.EqualsCI("busmgr@sarand.com")))
{
// Record invalid login attempt.
securityItemUser.InvalidLoginCount++;
@@ -201,16 +204,16 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
/// <summary>
/// Identify the organisation for the user to login to - either last selected (via SysParam) or first in list.
/// </summary>
private SbmAssociation GetOrganisationAssociationForSignIn(SbmAccountMgr accountMgrForUser, Model_Security model, ISbmUserOrganisationContext userContext)
private SbmAssociation GetOrganisationAssociationForSignIn(SbmInternals internalsForUser, Model_Security model, ISbmUserOrganisationContext userContext)
{
// Previously selected organisation is stored in user params (SysParam table).
SbmSysParamCache sysParamCache = new SbmSysParamCache(userContext, userContext.UserAffiliateId);
SbmSysParamCache sysParamCache = new SbmSysParamCache(internalsForUser, userContext.UserAffiliateId);
SysId affiliateIdOrganisation = SysId.ToSysId(sysParamCache.GetUserParamValue(SbmSysParamCache.ParamName_SelectedCompany));
SbmAssociation associationOrganisation = null;
List<SysIdString> supervisedOrganisations = accountMgrForUser.GetAffiliatesSupervisedBy(userContext.UserAffiliateId);
List<SysIdString> supervisedOrganisations = internalsForUser.AccountMgr.GetAffiliatesSupervisedBy(userContext.UserAffiliateId);
foreach (SysIdString supervisedOrganisation in supervisedOrganisations)
{
SbmAssociation associationOrganisationCandidate = accountMgrForUser.GetAssociationByOwnerTypeTarget(supervisedOrganisation.Id, Sbm.AssociationType.Internal, supervisedOrganisation.Id);
SbmAssociation associationOrganisationCandidate = internalsForUser.AccountMgr.GetInternalAssociation(supervisedOrganisation.Id);
if (associationOrganisationCandidate == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve internal association for affiliate Id: {SysId.ToString(supervisedOrganisation.Id)}.");
@@ -374,7 +377,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (storePasswordParams.IsValid())
{
// Instance Repository configured on Control database identified by Context.
SbmSessionContext sessionContextForUser = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(storePasswordParams.RepositoryContext);
SbmSessionContext sessionContextForUser = SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(storePasswordParams.RepositoryContext);
if (sessionContextForUser != null)
{
// Consoles and Managers must be associated with the specific context for the User storing the password.
@@ -425,7 +428,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve affiliate details."));
// Validate password data.
model.ValidateChangePasswordData(securityItemUser, affiliateUser, responseData);
model.ValidateChangePasswordData(internalsForStorePassword, securityItemUser, affiliateUser, responseData);
if (responseData.HasControlErrors())
return Json(responseData);
@@ -440,6 +443,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++)
{
// Compare history password to new value.
// ToDo Switch to internals.SecurityConsole.PasswordMatches().
if (SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password, securityItemUser.PasswordHistory[passwordHistoryIdx]))
{
// New password found in history - remove it.
@@ -494,7 +498,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
if (responseData.HasControlErrors()) return Json(responseData);
// Instance Repository configured on Control database identified by Context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(model.RepositoryContext);
SbmSessionContext sessionContext = SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(model.RepositoryContext);
if (sessionContext != null)
{
SbmSessionData_Portal sessionDataForUser = new SbmSessionData_Portal(sessionContext, model.RepositoryContext, null, null, null, null);
@@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
@@ -19,6 +18,9 @@ using System.Threading.Tasks;
using Sarand.BusinessMgr.Web.Portal.Helpers;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Controllers.Home;
using Sarand.BusinessMgr.Web.Portal.Models.Security;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
{
@@ -46,13 +48,26 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
//-------------------------------------------------------------------
[HttpGet]
public IActionResult Signin()
[Route("Security/Signin/{context=}/{email=}")]
public IActionResult Signin(String context, String email)
{
// Redirect home if signed-in.
if (ValidUserSession)
return RedirectToAction("", "");
// Sanitise request parameters.
if (SbmPasswordHelper.IsValidPassword(context) && !SbmPasswordHelper.IsValidPassword(email))
{
// Switch context and email.
String emailTemp = email;
email = context;
context = email;
}
// Initialise model with optional paramaters from request path.
Model_Security model = new Model_Security(Localiser);
model.RepositoryContext = context;
model.EmailAddress = email;
return View(model);
}
@@ -79,7 +94,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Security
String logPrefix = $"{SysUtil.Fn} 'Request Password' parameters supplied but ";
String logSuffix = changePasswordParams.GetValidParams().Concat("", " ", ".");
// Instance Repository configured on Control database identified by Context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Portal.GetControlSessionContextByRepositoryContext(changePasswordParams.RepositoryContext);
SbmSessionContext sessionContext = SbmCoreInstanceHelper_Portal.GetSessionContextByRepositoryContext(changePasswordParams.RepositoryContext);
if (sessionContext != null)
{
// Consoles and Managers must be associated with the specific context.
@@ -1,8 +1,9 @@
using Microsoft.AspNetCore.Mvc;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Web.Portal.Models.Transactions;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.BusinessMgr.Web.Portal.Models.Contacts;
using Sarand.BusinessMgr.Web.Portal.Models.Transactions;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -11,8 +12,6 @@ using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using static Sacs.Web.Components.SaController.AjaxResponse_Data;
using Sarand.BusinessMgr.Web.Portal.Components;
namespace Sarand.BusinessMgr.Web.Portal.Controllers.Transactions
{
@@ -29,7 +28,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Controllers.Transactions
public String Reference { get; set; }
public String Narrative { get; set; }
// Field values.
public FieldValuesData Field { get; } = new FieldValuesData();
public AjaxResponse_Data.FieldValuesData Field { get; } = new AjaxResponse_Data.FieldValuesData();
}
private enum TransactionDataGroup
{
@@ -0,0 +1,40 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Dbas.Data;
using System;
using System.Collections.Generic;
namespace Sarand.BusinessMgr.Web.Portal.Helpers
{
//=======================================================================
/// <summary>
/// Core Instance utility functions.
/// </summary>
public class SbmCoreInstanceHelper_Portal
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Session Context by Repository Context.
//-------------------------------------------------------------------
/// <summary>
/// Retrieve Session Context for Core database with specified Repository Context.
/// <br/>- Returns null is Context not found or is not active.
/// </summary>
public static SbmSessionContext GetSessionContextByRepositoryContext(String repositoryContext)
{
SbmApplication_Portal app = SbmApplication_Portal.Instance;
return app?.GetControlSessionContextByRepositoryContext(repositoryContext);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -1,125 +0,0 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Web.Portal.App;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Dbas.Data;
using System;
using System.Collections.Generic;
namespace Sarand.BusinessMgr.Web.Portal.Helpers
{
//=======================================================================
// Portal Session Context utility functions.
//=======================================================================
public class SbmSessionContextHelper_Portal
{
//-------------------------------------------------------------------
// Control Session Context.
//-------------------------------------------------------------------
public static SbmSessionContext GetControlSessionContextByRepositoryContext(String repositoryContext)
{
SbmApplication_Portal app = SbmApplication_Portal.Instance;
return app?.GetControlSessionContextByRepositoryContext(repositoryContext);
}
//-------------------------------------------------------------------
// Session Contexts.
//-------------------------------------------------------------------
public static List<SbmSessionContext> GetSessionContextsByRepositoryContext(String repositoryContext)
{
Dictionary<int, SbmSessionContext> sessionContexts = new Dictionary<int, SbmSessionContext>();
SbmApplication_Portal app = SbmApplication_Portal.Instance;
// Control session context.
// - Will be populated if not previously referenced by Repository Context.
SbmSessionContext controlSessionContext = app.GetControlSessionContextByRepositoryContext(repositoryContext);
if (controlSessionContext != null)
sessionContexts[controlSessionContext.Index] = controlSessionContext;
// Core Session Contexts.
foreach (ushort sessionContextIdx in app.GetSessionContextIdxs())
{
// Retrieve the session context.
SbmSessionContext sessionContext = app.GetSessionContextByIndex(sessionContextIdx);
if (sessionContext == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve SessionContext for idx: " + sessionContextIdx);
continue;
}
// Verify Repository Context.
HashSet<string> repositoryContexts = app.GetRepositoryContexts(sessionContext);
if (!repositoryContexts.ContainsCI(repositoryContext))
continue;
sessionContexts[sessionContext.Index] = sessionContext;
}
return new List<SbmSessionContext>(sessionContexts.Values);
}
//-------------------------------------------------------------------
// Session Contexts for Repository Context and User Email Address.
//-------------------------------------------------------------------
[Obsolete("Deprecated - BusMgr databases only referenced via Control database rather than in application config.")]
/// <summary>
/// Identify the session context(s) that corresponds with the BusinessMgr
/// repository by context for the specified user by email address.
/// </summary>
public static List<SbmSessionContext> GetSessionContextForRepositoryContextUserEmail(String repositoryContext, String emailAddress)
{
Dictionary<int, SbmSessionContext> sessionContexts = new Dictionary<int, SbmSessionContext>();
String alias_SecurityItem = "SecItm";
String alias_Affiliate = "Affil";
if (StringUtil.IsEmpty(emailAddress)) return new List<SbmSessionContext>(sessionContexts.Values);
if (SacsSystem.DebugMode) SaLogger.Info($"{SysUtil.Fn} Searching for database. Identifier: {repositoryContext}. Email address: {emailAddress}");
// Get the session context indices defined by the application.
SbmApplication_Web app = SbmGlobals_Web.Application;
foreach (SbmSessionContext sessionContext in GetSessionContextsByRepositoryContext(repositoryContext))
{
// Verify Repository Context.
HashSet<string> repositoryContexts = app.GetRepositoryContexts(sessionContext);
if (!repositoryContexts.ContainsCI(repositoryContext))
continue;
// Retrieve database.
ISacsDatabase db = app.GetBusMgrDatabase(sessionContext);
if (db == null)
{
SaLogger.Warn($"{SysUtil.Fn} Failed to retrieve Database for idx: " + sessionContext.Index);
continue;
}
if (SacsSystem.DebugMode) SaLogger.Info($"{SysUtil.Fn} Database: " + db.DatabaseName);
// Query to check for Security Item matching the email with associated Affiliate.
// NB This is done independently for each database in case there are different
// DBMSs involved with different value formatting or syntax rules.
DbQuery qry = new DbQuery(db.DbmsType);
qry.Tables.Add(SaSecurityDbDfn.GetTableName(SaSecurityDbDfn.TableIdx.SaSecItem), alias_SecurityItem);
qry.Columns.Add(SaSecurityDbDfn.GetColumnNameQual(SaSecurityDbDfn.ColumnIdx.SaSecItem_Id, alias_SecurityItem));
qry.Columns.Add(SaSecurityDbDfn.GetColumnNameQual(SaSecurityDbDfn.ColumnIdx.SaSecItem_Id, alias_SecurityItem));
qry.Filters.Add(SaSecurityDbDfn.GetColumnNameQual(SaSecurityDbDfn.ColumnIdx.SaSecItem_EmailAddress, alias_SecurityItem) + "='" + DbQuery.FormatForCondition(emailAddress) + "'");
// Join to the Affiliate table.
DbQueryJoin joinAffiliate = new DbQueryJoin(DbJoinType.FullOuter);
joinAffiliate.Table = new StringPair(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Affiliate), alias_Affiliate);
joinAffiliate.Filters.Add(SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_UserId, alias_Affiliate) + "=" + SaSecurityDbDfn.GetColumnNameQual(SaSecurityDbDfn.ColumnIdx.SaSecItem_Id, alias_SecurityItem));
// Execute query.
using (DbResultSet resultSet = DbResultSet_DataReader.ExecuteQuery(db, qry.BuildQuery()))
{
if (resultSet != null && resultSet.NextRecord())
{
if (SacsSystem.DebugMode) SaLogger.Info($"{SysUtil.Fn} Database contains email: " + db.DatabaseName);
sessionContexts[sessionContext.Index] = sessionContext;
}
}
}
return new List<SbmSessionContext>(sessionContexts.Values); ;
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -391,8 +391,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Commodities
bool isProduct = commodityType != Sbm.CommodityType.Service;
bool isService = commodityType == Sbm.CommodityType.Service;
bool importedFromAccounts = Internals.AccountsDfn.ItemIsImportedFromAccounts(commodityItemId);
bool managedByAccounts = Internals.AccountsDfn.IsItemTypeManagedByAccounts(Sbm.ItemType.Commodity);
bool importedFromAccounts = Internals.AccountsConsole.ItemIsImportedFromAccounts(commodityItemId);
bool managedByAccounts = Internals.AccountsConsole.IsItemTypeManagedByAccounts(Sbm.ItemType.Commodity);
bool showNotes = true;
//---------------------------------------------------------------
@@ -306,13 +306,13 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
bool isInternal = (associationType == Sbm.AssociationType.Internal);
// Accounts interface.
bool managedByAccounts = Internals.AccountsDfn.ItemIsImportedFromAccounts(associationItemId);
bool managedByAccounts = Internals.AccountsConsole.ItemIsImportedFromAccounts(associationItemId);
if (managedByAccounts) config.ManagedByAccounts = true;
// Determine pricing options.
bool localPricing =
(isCustomer && Internals.AccountsDfn.UseLocalCustomerPricing()) ||
(isSupplier && Internals.AccountsDfn.UseLocalSupplierPricing());
(isCustomer && Internals.AccountsConsole.UseLocalCustomerPricing()) ||
(isSupplier && Internals.AccountsConsole.UseLocalSupplierPricing());
if (localPricing) config.LocalPricing = true;
// Update dialog title.
@@ -443,21 +443,21 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
else if (managedByAccounts)
{
Sage.ItemType sageItemType = isCustomer ? Sage.ItemType.Customer : Sage.ItemType.Supplier;
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountManagerCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountManagerCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.AccountManager}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountHandlerCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountHandlerCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.AccountHandler}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountTypeCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountTypeCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.AccountType}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountRatingCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_AccountRatingCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.AccountRating}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactAreaCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactAreaCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.ContactArea}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactHandlerCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactHandlerCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.ContactHandler}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactMethodCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactMethodCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.ContactMethod}");
if (Internals.AccountsDfn.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactCallCycleCode, sageItemType))
if (Internals.AccountsConsole.SourcedFromSage(SbmDbDfn.ColumnIdx.Association_ContactCallCycleCode, sageItemType))
config.Field.Readonly.Add($"{ItemField.ContactCallCycle}");
}
}
@@ -244,7 +244,7 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Contacts
bool isGroup = SbmAffiliate.IsContactGroup(affiliateType);
if (isGroup) config.IsGroup = true;
bool importedFromAccounts = Internals.AccountsDfn.ItemIsImportedFromAccounts(affiliateItemId);
bool importedFromAccounts = Internals.AccountsConsole.ItemIsImportedFromAccounts(affiliateItemId);
bool showNotes = true;
// Id.
@@ -0,0 +1,159 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Components;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
using Sarand.BusinessMgr.Web.Portal.Components;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
namespace Sarand.BusinessMgr.Web.Portal.Models.Security
{
//=======================================================================
public class Model_Demo : SbmModel_Portal
{
//-------------------------------------------------------------------
// Configuration.
/// <summary>Prefix for field names.</summary>
public const String FieldNamePrefix = "Account";
/// <summary>Item fields.</summary>
public enum ItemField
{
EmailAddress,
FirstName,
LastName,
Password,
PasswordConfirm,
}
/// <summary>
/// Identifier used by form fields to show control specific messages generated by model validation etc.
/// <para>- Both page and model should use this method to consistently generate the field name.</para>
/// </summary>
public static String GetFieldName(ItemField field)
{
return $"{FieldNamePrefix}{field}";
}
//-------------------------------------------------------------------
// Construction.
public Model_Demo(SbmLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Page properties.
public int RegisterDemoAccountLinkExpiresMinutes { get; set; } = 12;
/// <summary>Whether data is complete and valid for registration.</summary>
public bool DemoAccountRegistrationValid { get; set; }
/// <summary>
/// Message to display if the registration data is incomplete
/// or invalid before redirecting to the Home page.
/// </summary>
public String DemoAccountRegistrationMessage { get; set; }
//-------------------------------------------------------------------
// Form properties.
public string EmailAddress { get; set; }
/// <summary>Request Demo Account Encrypted params.</summary>
public String RequestParams { get; set; }
// Name.
public string FirstName { get; set; }
public string LastName { get; set; }
// Password and confirmation.
public string Password { get; set; }
public string PasswordConfirm { get; set; }
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// Demo Account Request.
public bool ValidateRequestData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
{
// Email address.
string controlName = GetFieldName(ItemField.EmailAddress);
responseData.SetControlValue(controlName, EmailAddress);
if (EmailAddress.IsEmpty())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
return !responseData.HasControlErrors();
}
// Demo Account Registration.
public bool ValidateRegisterData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
// Email address.
if (EmailAddress != null)
{
string controlName = GetFieldName(ItemField.EmailAddress);
EmailAddress = EmailAddress.ToLowerInvariant();
responseData.SetControlValue(controlName, EmailAddress);
if (StringUtil.IsBlank(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
else
{
}
}
// First Name.
if (FirstName != null)
{
string controlName = GetFieldName(ItemField.FirstName);
responseData.SetControlValue(controlName, FirstName);
if (StringUtil.GetLength(FirstName) > GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_FirstName))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_FirstName)]);
}
// Last Name.
if (LastName != null)
{
string controlName = GetFieldName(ItemField.LastName);
responseData.SetControlValue(controlName, LastName);
if (StringUtil.IsBlank(LastName))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(LastName) > GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_LastName))
responseData.SetControlError(controlName, Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_LastName)]);
}
// Password.
if (Password != null)
{
// NB Do not return the password values in the response.
string controlName = GetFieldName(ItemField.Password);
if (Password.IsEmpty())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SbmPasswordHelper.IsValidPassword(Password))
responseData.SetControlError(controlName, Localiser.GetText("msg.warn.password.invalid", new object[] { SbmPasswordHelper.Params.MinLength, SbmPasswordHelper.Params.MinLengthNoComplexity }));
else if (PasswordConfirm != null)
{
// Password confirm.
// NB Do not return the password values in the response.
controlName = GetFieldName(ItemField.PasswordConfirm);
if (!PasswordConfirm.Equals(Password))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -4,7 +4,7 @@ using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control;
using Sarand.BusinessMgr.Web.Portal.Components;
namespace Sarand.BusinessMgr.Web.Portal.Models
namespace Sarand.BusinessMgr.Web.Portal.Models.Home
{
//=======================================================================
public class Model_Home : SbmModel_Portal
@@ -1,5 +1,6 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Components;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
using Sarand.BusinessMgr.Web.Portal.Components;
@@ -9,9 +10,10 @@ using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
using System.Threading.Tasks;
namespace Sarand.BusinessMgr.Web.Portal.Models
namespace Sarand.BusinessMgr.Web.Portal.Models.Security
{
//=======================================================================
public class Model_Security : SbmModel_Portal
@@ -27,39 +29,39 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
//-------------------------------------------------------------------
// Page configuration.
public bool RequestPasswordMode { get { return !StringUtil.IsEmpty(rpe); } }
public bool RequestPasswordMode { get { return !rpe.IsEmpty(); } }
//-------------------------------------------------------------------
// Form properties.
/// <summary>Database config identifier.</summary>
public String RepositoryContext { get; set; }
public String EmailAddress { get; set; }
public String PasswordCurrent { get; set; }
public String Password { get; set; }
public String PasswordConfirm { get; set; }
public string RepositoryContext { get; set; }
public string EmailAddress { get; set; }
public string PasswordCurrent { get; set; }
public string Password { get; set; }
public string PasswordConfirm { get; set; }
public bool KeepMeSignedIn { get; set; }
/// <summary>Request Password Encrypted params - to allow Change Password without session or requiring old password.</summary>
public String rpe { get; set; }
public string rpe { get; set; }
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// Sign-in.
public bool ValidateSignInData(SbmController_Web.AjaxResponse_Data responseData)
public bool ValidateSignInData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
{
// Database context.
String controlName = nameof(RepositoryContext);
string controlName = nameof(RepositoryContext);
responseData.SetControlValue(controlName, RepositoryContext);
if (StringUtil.IsEmpty(RepositoryContext))
if (RepositoryContext.IsEmpty())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
}
{
// Email address.
String controlName = nameof(EmailAddress);
string controlName = nameof(EmailAddress);
responseData.SetControlValue(controlName, EmailAddress);
if (StringUtil.IsEmpty(EmailAddress))
if (EmailAddress.IsEmpty())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
@@ -68,8 +70,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
{
// Password.
// NB Do not return the password value in the response.
String controlName = nameof(Password);
if (StringUtil.IsEmpty(Password))
string controlName = nameof(Password);
if (Password.IsEmpty())
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
}
@@ -78,19 +80,19 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
//-------------------------------------------------------------------
// Change password.
public bool ValidateChangePasswordData(SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, SbmController_Web.AjaxResponse_Data responseData)
public bool ValidateChangePasswordData(SbmInternals internals, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
// Validate Passwords.
// NB Do not return the password values in the response.
// NB Only validate populated values - any null values are not part of the form for this request.
// - 'Current' password is not shown when changing password from 'Request Password' email link.
if (PasswordCurrent != null && StringUtil.IsEmpty(PasswordCurrent))
if (PasswordCurrent != null && PasswordCurrent.IsEmpty())
responseData.SetControlError(nameof(PasswordCurrent), Localiser["msg.validation.mandatory.value"]);
if (StringUtil.IsEmpty(Password))
if (Password.IsEmpty())
responseData.SetControlError(nameof(Password), Localiser["msg.validation.mandatory.value"]);
if (StringUtil.IsEmpty(PasswordConfirm))
if (PasswordConfirm.IsEmpty())
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.mandatory.value"]);
if (!StringUtil.IsEmpty(Password) && !StringUtil.IsEmpty(PasswordConfirm))
if (!Password.IsEmpty() && !PasswordConfirm.IsEmpty())
{
if (!Password.Equals(PasswordConfirm))
responseData.SetControlError(nameof(PasswordConfirm), Localiser["msg.validation.invalid.value"]);
@@ -100,9 +102,9 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
if (!responseData.HasControlErrors())
{
if (PasswordCurrent != null && !SbmPasswordHelper.VerifyHashedPassword(securityItemUser, PasswordCurrent))
if (PasswordCurrent != null && !internals.SecurityConsole.PasswordMatches(securityItemUser, PasswordCurrent, internals.DbUpdateInfo))
responseData.SetControlError(nameof(PasswordCurrent), Localiser["security.change.password.current.invalid"]);
if (SbmPasswordHelper.VerifyHashedPassword(securityItemUser, Password))
if (internals.SecurityConsole.PasswordMatches(securityItemUser, Password, internals.DbUpdateInfo))
responseData.SetControlError(nameof(Password), Localiser["security.change.password.not.changed"]);
}
@@ -111,21 +113,24 @@ namespace Sarand.BusinessMgr.Web.Portal.Models
//-------------------------------------------------------------------
// Request Password.
public bool ValidateRequestPasswordData(SbmController_Web.AjaxResponse_Data responseData)
public bool ValidateRequestPasswordData(Sacs.Web.Components.SaController.AjaxResponse_Data responseData)
{
if (RepositoryContext != null)
{
// Database context.
String controlName = nameof(RepositoryContext);
string controlName = nameof(RepositoryContext);
responseData.SetControlValue(controlName, RepositoryContext);
if (StringUtil.IsEmpty(RepositoryContext))
if (StringUtil.IsBlank(RepositoryContext))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
}
if (EmailAddress != null)
{
// Email address.
String controlName = nameof(EmailAddress);
string controlName = nameof(EmailAddress);
EmailAddress = EmailAddress.ToLowerInvariant();
responseData.SetControlValue(controlName, EmailAddress);
if (StringUtil.IsEmpty(EmailAddress))
if (StringUtil.IsBlank(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(EmailAddress))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
@@ -546,8 +546,8 @@ namespace Sarand.BusinessMgr.Web.Portal.Models.Transactions
bool isSales = SbmTransaction.IsSalesType(transactionType);
bool isPurchase = SbmTransaction.IsPurchaseType(transactionType);
bool importedFromAccounts = Internals.AccountsDfn.ItemIsImportedFromAccounts(transactionItemId);
bool managedByAccounts = Internals.AccountsDfn.IsItemTypeManagedByAccounts(Sbm.ItemType.Transaction);
bool importedFromAccounts = Internals.AccountsConsole.ItemIsImportedFromAccounts(transactionItemId);
bool managedByAccounts = Internals.AccountsConsole.IsItemTypeManagedByAccounts(Sbm.ItemType.Transaction);
bool showNotes = true;
//---------------------------------------------------------------
@@ -0,0 +1,153 @@
@* Demo Instance User Registration page *@
@using Sarand.Net.Standard.Base.Security
@model Model_Demo
@inject SbmLocaliser Localiser
@{
ViewData["Title"] = "Demo Registration";
Model.AdditionalFiles_JS.Add("js/sbm-demo.js");
}
<div class="">
<div class="sbm-panel-form DemoRegister">
<div class="sbm-header"><div class="sbm-caption">@Localiser["caption.register.demo.account"]</div></div>
<div class="sbm-content" style="max-height:none;">
@if (Model.DemoAccountRegistrationValid)
{
@using (@Html.BeginForm("", null, FormMethod.Post, new { @id = "frmDemoRegister", @class = "sbm-form", @onSubmit = "return false;" }))
{
@Html.HiddenFor(model => model.RequestParams, new { @id = "" })
<div class="spacer2"></div>
<div class="sbm-form-control @Model_Demo.GetFieldName(Model_Demo.ItemField.EmailAddress)">
<div class="row">
<div class="col-sm-4">
<div class="sbm-label">
<label for="ifEmailAddress"><span>@Localiser["label.email"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
@Html.TextBoxFor(model => model.EmailAddress, new { @id = "", @class = "AccountEmailAddress sbm-input lower", @readonly = true, @maxlength = @Model.GetControlMaxLength(SaSecurityDbDfn.ColumnIdx.SaSecItem_EmailAddress) })
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
<div class="spacer"></div>
<div class="sbm-form-control @Model_Demo.GetFieldName(Model_Demo.ItemField.FirstName)">
<div class="row">
<div class="col-sm-4">
<div class="sbm-label">
<label for="ifFirstName"><span>@Localiser["label.name.first"]</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
<div class="row">
<div class="col-8">
@Html.TextBoxFor(model => model.FirstName, new { @id = "", @class = "AccountFirstName sbm-input", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_FirstName) })
</div>
</div>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
<div class="spacer"></div>
<div class="sbm-form-control @Model_Demo.GetFieldName(Model_Demo.ItemField.LastName)">
<div class="row">
<div class="col-sm-4">
<div class="sbm-label">
<label for="ifLastName"><span>@Localiser["label.name.last"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
<div class="row">
<div class="col-8">
@Html.TextBoxFor(model => model.LastName, new { @id = "", @class = "AccountLastName sbm-input", @maxlength = @Model.GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_LastName) })
</div>
</div>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
<div class="spacer"></div>
<div class="sbm-form-control @Model_Demo.GetFieldName(Model_Demo.ItemField.Password)">
<div class="row">
<div class="col-sm-4">
<div class="sbm-label">
<label for="ifPassword"><span>@Localiser["label.password"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
<div class="row">
<div class="col-8">@Html.PasswordFor(model => model.Password, new { @id = "", @class = "AccountPassword sbm-input", @maxlength = @Model.PasswordMaxLength })</div>
<div class="col-4"><div id="" class="AccountPasswordStrength sbm-password-strength"></div></div>
</div>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
<div class="spacer"></div>
<div class="sbm-form-control @Model_Demo.GetFieldName(Model_Demo.ItemField.PasswordConfirm)">
<div class="row">
<div class="col-sm-4">
<div class="sbm-label">
<label for="ifPasswordConfirm"><span>@Localiser["label.password.confirm"]</span><span class="required">&nbsp;*</span></label>
</div>
</div>
<div class="col-sm">
<div class="sbm-control">
<div class="row">
<div class="col-8">
@Html.PasswordFor(model => model.PasswordConfirm, new { @id = "", @class = "AccountPasswordConfirm sbm-input", @maxlength = @Model.PasswordMaxLength })
</div>
</div>
</div>
<div class="sbm-message"></div>
</div>
</div>
</div>
<div class="spacer2"></div>
<div class="">
<div id="pbRegister" class="sbm-button-action fullwidth pointer" style="margin:16px 0;">@Localiser["label.register"]</div>
</div>
}
}
else
{
@* Demo Account Registration not valid. *@
<div class="spacer2"></div>
<div class="">
@(new Microsoft.AspNetCore.Html.HtmlString(Localiser.HtmlEncode(StringUtil.OnBlank(Model.DemoAccountRegistrationMessage)).Replace("\n", "<br/>")))
</div>
<div class="spacer4"></div>
<div class="">You will shortly be redirected to the Home page.</div>
<div class="spacer4"></div>
<div class="">Alternatively, select the 'Home' menu option at the top of the page.</div>
<div class="spacer4"></div>
<script type="text/javascript">
setTimeout(function () { sbm.doProgress('Page Navigation', 'Redirecting to Home page.\n\nPlease wait ...'); setTimeout(function () { sbm.goToPage('Home'); }, 3000); }, 5000);
</script>
}
</div>
</div>
</div>
@@ -0,0 +1,50 @@
@* Demo Instance User Request page *@
@using Sarand.Net.Standard.Base.Security
@model Model_Demo
@inject SbmLocaliser Localiser
@{
ViewData["Title"] = "Demo User Request";
Model.AdditionalFiles_JS.Add("js/sbm-demo.js");
}
<div class="">
<div class="sbm-panel-form DemoRequest">
<div class="sbm-header"><div class="sbm-caption">@Localiser["caption.request.demo.account"]</div></div>
<div class="sbm-content" style="max-height:none;">
@using (@Html.BeginForm("", null, FormMethod.Post, new { @id = "frmDemoRequest", @class = "sbm-form", @onSubmit = "return false;" }))
{
<div class="spacer2"></div>
<div class="sbm-form-control EmailAddress" style="margin:0 10%;">
<div class="sbm-label">
<label for="ifEmailAddress"><span>@Localiser["label.email"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sbm-control">
@Html.TextBoxFor(model => model.EmailAddress, new { @id = "ifEmailAddress", @class = "sbm-input lower", @maxlength = @Model.GetControlMaxLength(SaSecurityDbDfn.ColumnIdx.SaSecItem_EmailAddress) })
</div>
<div class="sbm-message"></div>
</div>
<div class="spacer4"></div>
<div class="" style="margin:0 10%;">
<div>Your request will be acknowledged by email that will contain a link to the Demo User Registration page with a time restriction of @(Model.RegisterDemoAccountLinkExpiresMinutes) mins.</div>
<div class="spacer2"></div>
<div>Follow this link, complete your registration details and you'll immediately have access to the demo environment.</div>
</div>
<div class="spacer4"></div>
<div class="" style="margin:0 30%;">
<div id="pbRequest" class="sbm-button-action fullwidth pointer" style="margin:16px 0;">@Localiser["label.request"]</div>
</div>
}
</div>
</div>
</div>
@@ -7,14 +7,81 @@
@if (Model.AwaitingLogin)
{
@* ------------------------------------------------------------------- *@
@* User not logged in. *@
<div class="text-center">
<h1 class="display-4">Welcome</h1>
</div>
<style>
.sbm-panel-home-info
{
height: 100%;
margin: 0 4px;
padding: 4px 12px;
font-size: 16px;
border: 2px solid #b0b0b0;
border-radius: 4px;
background-color: #fff;
}
.sbm-panel-home-info div
{
margin: 0 0 8px 0;
font-size: 16px;
line-height: 1.25em;
}
</style>
<div class="row">
<div class="col-sm-6 sbm-flex-column">
<div class="sbm-flex-1">
<div class="sbm-panel-home-info" style="border-color:var(--color-KellyGreen);">
<h1>What's On Offer</h1>
<div class="">
Business Manager helps you look after the day-to-day operational data necsssary in running your business.
</div>
<div class="">
&bull; Contacts - your customers and suppliers.
</div>
<div class="">
&bull; Products and services that you offer.
</div>
<div class="">
&bull; Sales and purchase orders.
</div>
<div class="">
&bull; Optional modules including stock, time recording, assets, accounts integration.
</div>
</div>
</div>
</div>
<div class="col-sm-6 sbm-flex-column">
<div class="spacer2 d-sm-none"></div>
<div class="">
<div class="sbm-panel-home-info" style="border-color:var(--color-RoyalBlue);">
<h1>Existing users</h1>
<div style="margin:12px 24px 8px 24px;"><button onclick="sbm.goToPage('Security')" style="padding:4px 12px;border-radius:4px;">@Localiser["label.signin"]</button></div>
</div>
</div>
<div class="spacer2"></div>
<div class="sbm-flex-1">
<div class="sbm-panel-home-info" style="border-color:var(--color-BrightPurple);">
<h1>Demo environment</h1>
<div>You can set up an account to access the demo environment and try out a selection of application modules in a matter of minutes.</div>
<div>Request access and you'll be emailed a link to register your account.</div>
<div style="margin:12px 24px 8px 24px;"><button onclick="sbm.goToPage('Demo/Request')" style="padding:4px 12px;border-radius:4px;">@Localiser["label.request"]</button></div>
<div>The demo data is reset every 24 hours.</div>
</div>
</div>
</div>
</div>
@* ------------------------------------------------------------------- *@
}
else
{
@* ------------------------------------------------------------------- *@
@* User Session is active. *@
<style>
@@ -47,7 +114,6 @@ else
<h1 class="display-4">Welcome</h1>
</div>
<div class="">
<table id="tblWelcome" class="table-hover">
<tr style="font-weight:bold;background-color:lightsteelblue;">
@@ -81,4 +147,5 @@ else
</table>
</div>
}
@* ------------------------------------------------------------------- *@
}
@@ -18,41 +18,53 @@
@if (!Model.RequestPasswordMode)
{
/* Current password - required when setting password within user session. */
<div class="spacer4"></div>
<div class="spacer2"></div>
<div class="sbm-form-control PasswordCurrent">
<div class="sbm-label"><label for="ifPasswordCurrent"><span>@Localiser["label.password.current"]</span><span class="required">&nbsp;*</span></label></div>
<div class="sbm-control">
@Html.PasswordFor(model => model.PasswordCurrent, new { @id = "ifPasswordCurrent", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })
<div class="row">
<div class="col-4">
<div class="sbm-label"><label for="ifPasswordCurrent"><span>@Localiser["label.password.current"]</span><span class="required">&nbsp;*</span></label></div>
</div>
<div class="col">
<div class="sbm-control">@Html.PasswordFor(model => model.PasswordCurrent, new { @id = "ifPasswordCurrent", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })</div>
<div class="sbm-message"></div>
</div>
</div>
<div class="sbm-message"></div>
</div>
}
else
{
/* 'Request Password' encrypted parameters from email link. */
@Html.HiddenFor(model => model.rpe, new { @id = "ifRpe" });
@Html.HiddenFor(model => model.rpe, new { @id = "ifRpe" })
}
<div class="spacer4"></div>
<div class="sbm-form-control Password">
<div class="sbm-label"><label for="ifPassword"><span>@Localiser["label.password"]</span><span class="required">&nbsp;*</span></label></div>
<div class="sbm-control">
@Html.PasswordFor(model => model.Password, new { @id = "ifPassword", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })
</div>
<div class="row">
<div class="col-auto sbm-label-text pt4">@Localiser["label.strength"]&nbsp;</div>
<div id="" class="col-auto"><div id="prgPasswordStrength" class="col-auto"></div></div>
<div class="col-4">
<div class="sbm-label"><label for="ifPassword"><span>@Localiser["label.password"]</span><span class="required">&nbsp;*</span></label></div>
</div>
<div class="col">
<div class="sbm-control">@Html.PasswordFor(model => model.Password, new { @id = "ifPassword", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })</div>
<div class="row">
<div class="col-8 sbm-label-text pt-2 text-right">@Localiser["label.strength"]&nbsp;</div>
<div class="col-4"><div id="" class="sbm-password-strength" style="width:90%;"></div></div>
</div>
<div class="sbm-message"></div>
</div>
</div>
<div class="sbm-message"></div>
</div>
<div class="spacer4"></div>
<div class="spacer2"></div>
<div class="sbm-form-control PasswordConfirm">
<div class="sbm-label"><label for="ifPasswordConfirm"><span>@Localiser["label.password.confirm"]</span><span class="required">&nbsp;*</span></label></div>
<div class="sbm-control">
@Html.PasswordFor(model => model.PasswordConfirm, new { @id = "ifPasswordConfirm", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })
<div class="row">
<div class="col-4">
<div class="sbm-label"><label for="ifPasswordConfirm"><span>@Localiser["label.password.confirm"]</span><span class="required">&nbsp;*</span></label></div>
</div>
<div class="col">
<div class="sbm-control">@Html.PasswordFor(model => model.PasswordConfirm, new { @id = "ifPasswordConfirm", @class = "sbm-input", @maxlength = Model.PasswordMaxLength })</div>
<div class="sbm-message"></div>
</div>
</div>
<div class="sbm-message"></div>
</div>
<div class="spacer4"></div>
@@ -63,7 +75,5 @@
}
</div>
</div>
</div>
@@ -1,4 +1,5 @@
@using Sarand.Net.Standard.Base.Security
@* Portal User Signin page *@
@using Sarand.Net.Standard.Base.Security
@model Model_Security
@inject SbmLocaliser Localiser
@{
@@ -102,7 +102,7 @@
@* Navigation bar *@
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Sarand BusinessMgr</a>
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">BusinessMgr</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
@@ -163,13 +163,13 @@
<div class="container">
<div class="row">
<div class="col-md-6 text-center text-md-left">@(Model.OrganisationName)</div>
<div class="col-md-6 text-center text-md-right">@(Model.CopyrightNotice) - Sarand BusinessMgr Portal</div>
<div class="col-md-6 text-center text-md-right">@(Model.CopyrightNotice) Sarand Ltd v@(Sbm.Version.GetAppVersion())</div>
</div>
</div>
</footer>
@* Form to allow page navigation. *@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmNavigate" })) { }
@using (@Html.BeginForm("", null, FormMethod.Post, new { @id = "frmNavigate" })) { }
<div id='sbm-please-wait'></div>
@* Scripts *@
@@ -2,10 +2,13 @@
@using Sarand.BusinessMgr.Net.Standard.Base.App
@using Sarand.BusinessMgr.Web.Portal.Components
@using Sarand.BusinessMgr.Web.Portal.Models
@using Sarand.BusinessMgr.Web.Portal.Models.Home
@using Sarand.BusinessMgr.Web.Portal.Models.Security
@using Sarand.BusinessMgr.Web.Portal.Models.Contacts
@using Sarand.BusinessMgr.Web.Portal.Models.Commodities
@using Sarand.BusinessMgr.Web.Portal.Models.Assets
@using Sarand.BusinessMgr.Web.Portal.Models.Vehicles
@using Sarand.BusinessMgr.Web.Portal.Models.Codes
@using Sarand.Net.Standard.Base.CodeTypes
@using Sarand.Net.Standard.Base.Utils
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@@ -16,11 +16,11 @@
},
"Send": {
"Using": 2,
"UserName": "businessmgr@sarand.com",
"Password": "sarand-busmgr-5apPh1re"
"UserName": "contact@busmgr.sarand.com",
"Password": "3mA1L:bu5m6R:2025#"
},
"Message": {
"AddressFrom": "DoNotReply@SaBusinessMgr.com"
"AddressFrom": "DoNotReply@BusMgr.Sarand.com"
}
}
}
@@ -25,7 +25,24 @@ div, button, input, select, textarea, table, tr, td
box-shadow: 0 0 0 2px #80808040 inset;
}
/* Fonts */
/* Responsive */
.sbm-flex-column
{
display: flex;
flex-direction: column;
}
.sbm-flex-row
{
display: flex;
flex-direction: row;
}
.sbm-flex-1
{
flex:1;
}
/* Common styles */
@@ -36,7 +53,7 @@ h1, h2, h3
h1
{
font-size: 14px;
font-size: 1.4em;
font-weight: bold;
margin: 6px 0 6px 0;
padding: 0;
@@ -44,7 +61,7 @@ h1
h2
{
font-size: 12px;
font-size: 1.2em;
font-weight: bold;
margin: 3px 0 6px 0;
padding: 0;
@@ -52,7 +69,7 @@ h2
h3
{
font-size: 11px;
font-size: 1.0em;
font-weight: bold;
margin: 3px 0 6px 0;
padding: 0;
@@ -230,7 +247,7 @@ td.action
width: 40%;
}
.width50pc
.halfwidth, .width50pc
{
width: 50%;
}
@@ -240,7 +257,17 @@ td.action
width: 100%;
}
.fullheight
.height25pc
{
height: 25%;
}
.halfheight, .height50pc
{
height: 50%;
}
.fullheight, .height100pc
{
height: 100%;
}
@@ -242,18 +242,17 @@
/* Password strength */
#prgPasswordStrength
.sbm-password-strength
{
width: 200px;
height: 18px;
margin: 6px 24px;
margin: 6px 12px;
border-color: #595959;
-moz-box-shadow: none;
-webkit-box-shadow: none;
overflow: hidden;
}
#prgPasswordStrength .ui-widget-header
.sbm-password-strength .ui-widget-header
{
margin: 0;
height: 20px;
@@ -263,21 +262,21 @@
border-radius: 0;
}
#prgPasswordStrength.amber .ui-widget-header
.sbm-password-strength.amber .ui-widget-header
{
background-color: #FFBF00;
border-color: #FFBF00;
}
#prgPasswordStrength.green .ui-widget-header
.sbm-password-strength.green .ui-widget-header
{
background-color: #238823;
border-color: #238823;
}
#prgPasswordStrength.ui-corner-all
.sbm-password-strength.ui-corner-all
{
border-radius: 8px;
border-radius: 6px;
}
/* The End */
@@ -52,7 +52,12 @@ body
}
}
/* Responsive */
/* Page layout */
#sbm-page-body
{
background-color: #f8ffff;
}
#sbm-page-body > .container, header > .container, footer > .container
{
@@ -166,7 +166,7 @@
}
as.onUpdateItem = function (env, response)
{
sbm.debug('onUpdateItem', response);
//sbm.debug('onUpdateItem', response);
if (!response.success) return;
let cfg = response.config || {};
as.clearItem(env, cfg);
@@ -24,7 +24,7 @@
}
ac.handleCodes = function (response)
{
sbm.debug('handleCodes', response);
//sbm.debug('handleCodes', response);
delete ac.awaitingRefreshResponse;
let $table = $('table', $pnl.table).find('tbody tr').remove().end();
$pnl.msgs.hide().empty();
@@ -135,7 +135,7 @@
}
ac.onUpdateItem = function (response)
{
sbm.debug('onUpdateItem', response);
//sbm.debug('onUpdateItem', response);
let frm = $frm.item;
ac.clearItem();
if (!response.success) return;
@@ -164,7 +164,7 @@
}
co.onUpdateItem = function (env, response)
{
sbm.debug('onUpdateItem', env, response);
//sbm.debug('onUpdateItem', env, response);
if (!response.success) return;
let cfg = response.config || {};
co.clearItem(env, cfg);
@@ -187,7 +187,7 @@
}
co.onStoreItem = function (env, response)
{
sbm.debug('onStoreItem', env, response);
//sbm.debug('onStoreItem', env, response);
sbm.refreshControlValues(response.controlValues);
if (!response.success) return;
env.$dlg.item.dialog('close');
@@ -243,7 +243,7 @@
//sbm.debug('editCommodity', prm);
let env = co.env.select;
env.prmEdit = prm;
sbm.debug(env, prm);
//sbm.debug(env, prm);
co.updateItem(env, prm.id);
}
co.onItemEdited = function (env, item)
@@ -231,7 +231,7 @@
{
//sbm.debug('onClickAssociationCount', env, item);
if (!item.id) return;
sbm.fn.listAssociations({ ownerId: item.id });
sbm.fn.listAssociations({ targetId: item.id });
}
//--------------------------------------------------------------
@@ -268,7 +268,7 @@
//sbm.debug('editContact', prm);
let env = co.env.select;
env.prmEdit = prm;
sbm.debug(env, prm);
//sbm.debug(env, prm);
co.updateItem(env, prm.id);
}
co.onItemEdited = function (env, item)
@@ -0,0 +1,78 @@
/*
* Security page scripts.
*/
(function (win, doc, undef)
{
"use strict";
let de = sbm.demo = { ajax: {}, $pnl: {}, $frm: {} };
//--------------------------------------------------------------
de.requestDemoUser = function ()
{
sbm.clearControlErrors();
de.ajax.request = de.ajax.request || { url: sbm.url.base + 'Demo/Ajax/Request', formSel: de.$frm.request, callbackFn: de.onRequestDemoUser };
sbm.doAjaxRequest(de.ajax.request, 50);
}
de.onRequestDemoUser = function (response)
{
//sbm.debug('onRequestDemoUser', response);
sbm.refreshControlValues(response.controlValues, de.$frm.request);
if (!response.success) return;
let msg = response.confirmMessage;
if (msg)
sbm.doAlert(msg.title, msg.text, function () { sbm.goToPage(''); });
else sbm.goToPage('');
}
//--------------------------------------------------------------
de.registerDemoUser = function ()
{
sbm.clearControlErrors();
de.ajax.register = de.ajax.register || { url: sbm.url.base + 'Demo/Ajax/Register', formSel: de.$frm.register, callbackFn: de.onRegisterDemoUser };
sbm.doAjaxRequest(de.ajax.register, 50);
}
de.onRegisterDemoUser = function (response)
{
//sbm.debug('onRegisterDemoUser', response);
sbm.refreshControlValues(response.controlValues, de.$frm.register);
if (!response.success) return;
let msg = response.confirmMessage;
if (msg)
sbm.doAlert(msg.title, msg.text, function () { sbm.goToPage(''); });
else sbm.goToPage('');
}
//--------------------------------------------------------------
de.doScorePassword = function ()
{
sbm.ajaxScorePassword = sbm.ajaxScorePassword || { url: sbm.url.base + 'Security/Ajax/ScorePassword', formSel: de.$frm.register, callbackFn: de.onScorePassword, noWaitIcon: true };
sbm.doAjaxRequest(sbm.ajaxScorePassword, 250);
}
de.onScorePassword = function (response)
{
var score = (response || {}).score || 0;
sbm.$prgPasswordStrength.progressbar("option", "value", score).removeClass('amber green').addClass(score > 3 ? 'green' : score > 2 ? 'amber' : '');
}
//--------------------------------------------------------------
$(function ()
{
de.$pnl.request = $('.DemoRequest');
de.$frm.request = de.$pnl.request.find('#frmDemoRequest');
de.$frm.request.on('click', '#pbRequest', function () { de.requestDemoUser(); });
de.$pnl.register = $('.DemoRegister');
de.$frm.register = de.$pnl.register.find('#frmDemoRegister');
de.$frm.register.on('keyup', '.AccountPassword', de.doScorePassword);
sbm.$prgPasswordStrength = de.$frm.register.find('.AccountPasswordStrength').progressbar({ 'max': 5 });
de.$frm.register.on('click', '#pbRegister', function () { de.registerDemoUser(); });
$('.sbm-input').on('input', function () { sbm.clearControlError(this); });
$(':input:enabled:visible:first').trigger('focus');
});
//--------------------------------------------------------------
}(window, window.document));
/* The End */
@@ -255,7 +255,7 @@
var opt = sbm.dlgOpts();
sbm.$dlg.alert = $('<div id="dlgAlert"><div id="dlgAlertMsg"></div></div>').dialog(opt);
}
$('#dlgAlertMsg', sbm.$dlg.alert).html(msg.replace(/\\n/g, '<br>'));
$('#dlgAlertMsg', sbm.$dlg.alert).html(msg.replace(/\n/g, '<br>'));
let btns = {};
btns[sbm.lbl.ok] = function () { $(this).dialog('close'); if (onOk) onOk(); };
sbm.$dlg.alert.dialog('option', { title: title || sbm.dlg.title.alert, buttons: btns });
@@ -278,7 +278,7 @@
btns[sbm.lbl.yes] = function () { $(this).dialog('close'); if (onOk) onOk(); };
btns[sbm.lbl.no] = function () { $(this).dialog('close'); if (onCancel) onCancel(); };
sbm.$dlg.confirm.dialog('option', { title: title || sbm.dlg.title.confirm, buttons: btns });
$('#dlgConfirmMsg').html(msg.replace(/\\n/g, '<br>'));
$('#dlgConfirmMsg').html(msg.replace(/\n/g, '<br>'));
sbm.openDialog(sbm.$dlg.confirm);
}
sbm.confirmItemRemove = function (fn)
@@ -300,7 +300,7 @@
opt.hide = { effect: 'fade', duration: 200 };
sbm.$dlg.progress = $('<div id="dlgProgress"><div id="dlgProgressMsg"></div></div>').dialog(opt);
}
$('#dlgProgressMsg').html(msg.replace(/\\n/g, '<br>'));
$('#dlgProgressMsg').html(msg.replace(/\n/g, '<br>'));
sbm.$dlg.progress.dialog('option', { title: title || sbm.dlg.title.progress });
if (delay > 0) sbm.toShowProgress = setTimeout(function () { sbm.$dlg.progress.dialog('open'); }, delay);
else sbm.$dlg.progress.dialog('open');
@@ -74,10 +74,10 @@
$(':input:enabled:visible:first').trigger('focus');
$('#ifEmailAddress,#ifPasswordCurrent,#ifPassword,#ifPasswordConfirm').on('input', function () { sbm.clearControlError(this); });
$('#frmChangePassword #ifPassword').on('keyup', sbm.doScorePassword);
sbm.$prgPasswordStrength = $('#frmChangePassword #prgPasswordStrength').progressbar({ 'max': 5 });
sbm.$prgPasswordStrength = $('#frmChangePassword .sbm-password-strength').progressbar({ 'max': 5 });
sbm.$frm.signIn = $('#frmSignIn');
sbm.$frm.signIn.on('keypress', '#ifEmailAddress,#ifPassword,#chkKeepMeSignedIn', function (e) { if (e.which == 13 && $('#ifEmailAddress', sbm.$frm.signIn).val() && $('#ifPassword', sbm.$frm.signIn).val()) sbm.doSignin(); });
sbm.$frm.signIn.on('click', '#pbSignIn', function () { sbm.doSignin(); }).on('keypress', '#pbSignIn', function (e) { if (e.which == 13) sbm.doSignin(); });;
sbm.$frm.signIn.on('click', '#pbSignIn', function () { sbm.doSignin(); }).on('keypress', '#pbSignIn', function (e) { if (e.which == 13) sbm.doSignin(); });
$('#ifPasswordCurrent,#ifPassword,#ifPasswordConfirm', $('#frmChangePassword')).on('keypress', function (e) { if (e.which == 13) sbm.doChangePassword(); });
$('#frmChangePassword #pbChangePassword').on('click', function () { sbm.doChangePassword(); });
$('#ifEmailAddress', $('#frmRequestPassword')).on('keypress', function (e) { if (e.which == 13) sbm.doRequestPassword(); });
@@ -24,7 +24,7 @@
}
vc.handleVehicleClasses = function (response)
{
sbm.debug('handleVehicleClasses', response);
//sbm.debug('handleVehicleClasses', response);
delete vc.awaitingRefreshResponse;
let $table = $('table', $pnl.table).find('tbody tr').remove().end();
$pnl.msgs.hide().empty();