Portal application - initial.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>Sarand.BusinessMgr.Net.Core</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.16" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsCoreWeb\SacsCoreWeb.csproj" />
|
||||
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardBase\SacsStandardBase.csproj" />
|
||||
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardDbas\SacsStandardDbas.csproj" />
|
||||
<ProjectReference Include="..\..\..\Common-VS\Workspace\SacsStandardProc\SacsStandardProc.csproj" />
|
||||
<ProjectReference Include="..\SaBusMgrStandardBase\SaBusMgrStandardBase.csproj" />
|
||||
<ProjectReference Include="..\SaBusMgrStandardDbas\SaBusMgrStandardDbas.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Web\Core\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,148 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.Consoles;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.CodeTypes;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Diary;
|
||||
using Sarand.Net.Standard.Base.Interfaces;
|
||||
using Sarand.Net.Standard.Base.IO;
|
||||
using Sarand.Net.Standard.Base.ItemData;
|
||||
using Sarand.Net.Standard.Base.ItemDocs;
|
||||
using Sarand.Net.Standard.Base.ItemOptions;
|
||||
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 Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SbmApplication_Web : SbmApplication
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
protected Sbm.InstanceType instanceType;
|
||||
protected String environmentName = "";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SbmApplication_Web() : base(new PropertySet())
|
||||
{
|
||||
WebApp = this;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override SbmSystem System { get { return System_Web; } }
|
||||
public SbmSystem_Web System_Web { get; protected set; }
|
||||
public static SbmApplication_Web WebApp { get; private set; }
|
||||
// Application instance.
|
||||
public override Sbm.InstanceType InstanceType { get { return instanceType; } }
|
||||
public override String EnvironmentName { get { return environmentName; } }
|
||||
public bool Development { get; protected set; }
|
||||
public String LoggingRootFolder { get; protected set; } = "";
|
||||
// Application components.
|
||||
public abstract String SessionCookieName { get; }
|
||||
public virtual SbmSessionContext SessionContext { get; protected set; }
|
||||
public abstract SbmSessionConfig SessionConfig { get; }
|
||||
public override IDatabaseInfo CreateBusMgrDbInfo(SbmSessionContext sessionContext) { return new DbDataItem.DatabaseInfo(GetBusMgrDatabase(sessionContext)); }
|
||||
// Configuration.
|
||||
public IConfiguration Configuration { get; protected set; }
|
||||
public IConfiguration SbmConfiguration { get; protected set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Logging.
|
||||
protected void LogApplicationStart(String fn)
|
||||
{
|
||||
// Log application start.
|
||||
List<StringPair> applicationParams = new List<StringPair>();
|
||||
applicationParams.Add("Host", SbmSystem.ComputerName);
|
||||
applicationParams.Add("Version", Sbm.Version.GetFullVersion());
|
||||
applicationParams.Add("Instance", InstanceType.ToString() + (!StringUtil.IsEmpty(SessionConfig.Instance) ? " [" + SessionConfig.Instance + "]" : ""));
|
||||
applicationParams.Add("Configuration", SbmSystem.DebugMode ? "Debug" : "Release");
|
||||
applicationParams.Add("Environment", EnvironmentName);
|
||||
applicationParams.Add("Database", SessionConfig.BusMgrDatabase.Location);
|
||||
applicationParams.Add("Application root", SbmSystem.ApplicationFolder);
|
||||
if (!StringUtil.IsEmpty(SessionConfig.Documents.RootFolder))
|
||||
applicationParams.Add("Documents root", SessionConfig.Documents.RootFolder);
|
||||
applicationParams.Add("Email context", SessionConfig.Email.Context + (!StringUtil.IsEmpty(EmailConfig.SMTP.Server) ? " [" + EmailConfig.SMTP.Server + "]" : ""));
|
||||
SaLogger.Info(fn + " Application start." + applicationParams.Select(item => StringUtil.PadRight(item.Item1 + ":", 20, ' ') + item.Item2).Concat("", "\n\t"), true);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected void InitialiseTemporaryLoggingFolder()
|
||||
{
|
||||
// Default logging folder - in case of startup failure.
|
||||
try
|
||||
{
|
||||
foreach (String folder in new String[] { @"D:\Sarand\Projects\User\AHoward\VS2017\Sbmonite\Logs" })
|
||||
{
|
||||
if (DirectoryUtil.DirectoryExists(folder))
|
||||
{
|
||||
SaLogger.LogFolder = folder;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Create consoles.
|
||||
public override SbmConfigConsole CreateConfigConsole(SbmSessionContext sessionContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaDiaryConsole CreateDiaryConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaSecurityConsole CreateSecurityConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaCodeTypeConsole CreateCodeTypeConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaReferenceDataConsole CreateReferenceDataConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaItemDataConsole CreateItemDataConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaItemDocConsole CreateItemDocConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaItemOptionConsole CreateItemOptionConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaInterfaceConsole CreateInterfaceConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SaUpdateLogConsole CreateUpdateLogConsole(SbmUserContext userContext)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
public override SbmEmailConsole CreateEmailConsole(SbmUserContext userContext)
|
||||
{
|
||||
return new SbmEmailConsole_Web(EmailConfig);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SbmLocaliser
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localisers are supplied by derived object.
|
||||
/// </summary>
|
||||
protected SbmLocaliser()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public abstract IStringLocalizer MainProperties { get; }
|
||||
public virtual List<IStringLocalizer> AlternativeProperties { get; } = new List<IStringLocalizer>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Generic phrase translation.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve localised text.</summary>
|
||||
public LocalizedString GetText(string key)
|
||||
{
|
||||
return GetText(key, new object[] { });
|
||||
}
|
||||
public LocalizedString GetText(string key, object param)
|
||||
{
|
||||
return GetText(key, new object[] { param });
|
||||
}
|
||||
public LocalizedString GetText(string key, object param1, object param2)
|
||||
{
|
||||
return GetText(key, new object[] { param1, param2 });
|
||||
}
|
||||
public LocalizedString GetText(string key, object[] parameters)
|
||||
{
|
||||
LocalizedString text = MainProperties.GetString(key, parameters);
|
||||
if (text.ResourceNotFound)
|
||||
{
|
||||
SaLogger.Debug(GetType().Name + ".GetText Key not found: " + key);
|
||||
// Look up key in alternative property files.
|
||||
foreach (IStringLocalizer properties in AlternativeProperties ?? new List<IStringLocalizer>())
|
||||
{
|
||||
text = properties.GetString(key, parameters);
|
||||
if (!text.ResourceNotFound)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
// Square bracket indexing.
|
||||
public LocalizedString this[String key]
|
||||
{
|
||||
get { return GetText(key); }
|
||||
}
|
||||
public LocalizedString this[String key, object param]
|
||||
{
|
||||
get { return GetText(key, param); }
|
||||
}
|
||||
public LocalizedString this[String key, object param1, object param2]
|
||||
{
|
||||
get { return GetText(key, param1, param2); }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localised HTML text.
|
||||
/// <para>Line delimiters changed to '<br/>'.</para>
|
||||
/// </summary>
|
||||
public HtmlString GetHtmlText(string key, String param1 = "", String param2 = "")
|
||||
{
|
||||
return GetHtmlText(key, new Object[] { param1, param2 });
|
||||
}
|
||||
/// <summary>
|
||||
/// Localised HTML text.
|
||||
/// <para>Line delimiters changed to '<br/>'.</para>
|
||||
/// </summary>
|
||||
public HtmlString GetHtmlText(string key, object[] parameters)
|
||||
{
|
||||
LocalizedString localisedText = GetText(key, parameters);
|
||||
String value = localisedText.Value;
|
||||
// Replace all line delimiters.
|
||||
value = value.Replace("\r\n", "\n").Replace("\n", "<br/>").Replace("\r", "<br/>");
|
||||
return new HtmlString(value);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Localised javascript string.
|
||||
/// <para>All quotes are escaped.</para>
|
||||
/// </summary>
|
||||
public LocalizedString GetJavascriptText(string key, String param1 = "", String param2 = "")
|
||||
{
|
||||
LocalizedString localisedText = GetText(key, param1, param2);
|
||||
return new LocalizedString(localisedText, EscapeJavascriptText(localisedText.Value), localisedText.ResourceNotFound);
|
||||
}
|
||||
public String EscapeJavascriptText(string value)
|
||||
{
|
||||
// Escape all quotes.
|
||||
value = value.Replace("'", "\\'").Replace("\"", "\\\"");
|
||||
return value;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Numeric and datetime formatting
|
||||
//-------------------------------------------------------------------
|
||||
public static String DateFormat_Default { get; } = "d-MMM-yyyy";
|
||||
public static String DateWithWeekdayFormat_Default { get; } = "ddd d-MMM-yyyy";
|
||||
public String FormatDate(DateTime value, Boolean includeWeekday = true)
|
||||
{
|
||||
String dateFormat = includeWeekday ? DateWithWeekdayFormat_Default : DateFormat_Default;
|
||||
return DateUtil.Format(value, dateFormat);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Specific phrase translation.
|
||||
//-------------------------------------------------------------------
|
||||
private class CodeCache
|
||||
{
|
||||
public List<TypeCodeDesc> affiliateTypeCodes;
|
||||
// To be completed.
|
||||
}
|
||||
private CodeCache codes = new CodeCache();
|
||||
|
||||
// Status.
|
||||
public String GetStatusCaption(SaStatus status)
|
||||
{
|
||||
// ToDo Status description localisation.
|
||||
return SacsSystem.GetStatusDesc(status);
|
||||
}
|
||||
|
||||
// Affiliate Type.
|
||||
public String GetAffiliateTypeTypeCaption(Sbm.AffiliateType participation)
|
||||
{
|
||||
if ((int)participation < 1) return "";
|
||||
if (codes.affiliateTypeCodes == null)
|
||||
codes.affiliateTypeCodes = SbmSystem.GetCodesOfType(null, Sbm.SystemCode.AffiliateType);
|
||||
// ToDo Affiliate Type localisation.
|
||||
return codes.affiliateTypeCodes.GetDescForType(participation);
|
||||
}
|
||||
|
||||
// To be completed.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,199 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmSessionConfig
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly List<String> environments = new List<string>();
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Construction.
|
||||
public SbmSessionConfig(String context, ConfigurationSection configSection, SbmSessionConfig defaultConfig)
|
||||
{
|
||||
Context = context;
|
||||
populateDefaults(defaultConfig);
|
||||
PopulateConfig(configSection);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
private void populateDefaults(SbmSessionConfig defaultConfig)
|
||||
{
|
||||
if (defaultConfig == null) return;
|
||||
Security.Password.MinLength = defaultConfig.Security.Password.MinLength;
|
||||
Security.SignIn.KeepLoggedIn.Allowed = defaultConfig.Security.SignIn.KeepLoggedIn.Allowed;
|
||||
Security.SignIn.KeepLoggedIn.CookieExpiresDays = defaultConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays;
|
||||
}
|
||||
private void PopulateConfig(ConfigurationSection configSection)
|
||||
{
|
||||
if (configSection != null)
|
||||
{
|
||||
// Environments.
|
||||
foreach (ConfigurationSection environment in configSection.GetSection("Environments").GetChildren())
|
||||
environments.Add(StringUtil.TrimAll(environment.Value));
|
||||
Instance = StringUtil.OnEmpty(configSection["Instance"], Instance);
|
||||
// Security.
|
||||
IConfigurationSection security = configSection.GetSection("Security");
|
||||
if (security.Exists())
|
||||
{
|
||||
// Security - Password.
|
||||
IConfigurationSection securityPassword = security.GetSection("Password");
|
||||
if (securityPassword.Exists())
|
||||
{
|
||||
Security.Password.MinLength = StringUtil.ToInt(securityPassword["MinLength"], Security.Password.MinLength);
|
||||
}
|
||||
// Security - Sign-Up.
|
||||
IConfigurationSection securitySignUp = security.GetSection("SignUp");
|
||||
if (securitySignUp.Exists())
|
||||
{
|
||||
}
|
||||
// Security - Sign-In.
|
||||
IConfigurationSection securitySignIn = security.GetSection("SignIn");
|
||||
if (securitySignIn.Exists())
|
||||
{
|
||||
IConfigurationSection keepLoggedIn = securitySignIn.GetSection("SignIn");
|
||||
if (keepLoggedIn.Exists())
|
||||
{
|
||||
Security.SignIn.KeepLoggedIn.Allowed = StringUtil.ToBool(StringUtil.OnEmpty(keepLoggedIn["Allowed"], Security.SignIn.KeepLoggedIn.Allowed.ToString()));
|
||||
Security.SignIn.KeepLoggedIn.CookieExpiresDays = StringUtil.ToInt(keepLoggedIn["CookieExpiresDays"], Security.SignIn.KeepLoggedIn.CookieExpiresDays);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Email.
|
||||
IConfigurationSection email = configSection.GetSection("Email");
|
||||
if (email.Exists())
|
||||
{
|
||||
Email.Context = email["Context"];
|
||||
PopulateEmailConfig(Email.ContactUs, email.GetSection("ContactUs"));
|
||||
PopulateEmailConfig(Email.Signup_Activate, email.GetSection("Signup").GetSection("Activate"));
|
||||
PopulateEmailConfig(Email.Signup_Welcome, email.GetSection("Signup").GetSection("Welcome"));
|
||||
}
|
||||
// Documents.
|
||||
IConfigurationSection documents = configSection.GetSection("Documents");
|
||||
if (documents.Exists())
|
||||
{
|
||||
Documents.RootFolder = StringUtil.OnEmpty(documents["RootFolder"], Documents.RootFolder);
|
||||
}
|
||||
// Logging.
|
||||
IConfigurationSection logging = configSection.GetSection("Logging");
|
||||
if (logging.Exists())
|
||||
{
|
||||
Logging.RootFolder = StringUtil.OnEmpty(logging["RootFolder"], Logging.RootFolder);
|
||||
}
|
||||
// Database.
|
||||
extractDatabaseConfig(BusMgrDatabase, configSection.GetSection("CoreDatabase"));
|
||||
// Variants.
|
||||
foreach (ConfigurationSection variantSection in configSection.GetSection("Variants").GetChildren())
|
||||
{
|
||||
// Variants override selected values but must match the application root folder to identify a specific instance.
|
||||
String applicationRootPath = variantSection["ApplicationRootFolder"];
|
||||
if (StringUtil.IsEmpty(applicationRootPath)) continue;
|
||||
if (!SbmSystem.ApplicationFolder.EqualsCI(applicationRootPath)) continue;
|
||||
PopulateConfig(variantSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void PopulateEmailConfig(EmailConfig.SpecificEmailConfig config, IConfigurationSection emailSection)
|
||||
{
|
||||
if (!emailSection.Exists()) return;
|
||||
foreach (var addressTo in emailSection.GetSection("AddressesTo").GetChildren())
|
||||
config.AddressesTo.Add(StringUtil.TrimAll(addressTo.Value));
|
||||
foreach (var addressCc in emailSection.GetSection("AddressesCc").GetChildren())
|
||||
config.AddressesCc.Add(StringUtil.TrimAll(addressCc.Value));
|
||||
foreach (var addressBcc in emailSection.GetSection("AddressesBcc").GetChildren())
|
||||
config.AddressesBcc.Add(StringUtil.TrimAll(addressBcc.Value));
|
||||
}
|
||||
private void extractDatabaseConfig(DatabaseConfig database, IConfigurationSection databaseSection)
|
||||
{
|
||||
if (!databaseSection.Exists()) return;
|
||||
database.Location = StringUtil.OnEmpty(databaseSection["Location"], database.Location);
|
||||
database.User = StringUtil.OnEmpty(databaseSection["User"], database.User);
|
||||
database.Password = StringUtil.OnEmpty(databaseSection["Password"], database.Password);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties.
|
||||
public String Context { get; }
|
||||
public List<String> Environments { get { return new List<String>(environments); } }
|
||||
public String Instance { get; set; } = "";
|
||||
// Security.
|
||||
public class SecurityConfig
|
||||
{
|
||||
public class PasswordConfig
|
||||
{
|
||||
public int MinLength { get; set; }
|
||||
}
|
||||
public PasswordConfig Password { get; } = new PasswordConfig();
|
||||
public class SignUpConfig
|
||||
{
|
||||
public class ActivationConfig
|
||||
{
|
||||
public int EmailLinkExpiresMins = Sbm.Config.Security.Activation.EmailLinkExpiresMins_Default;
|
||||
}
|
||||
public ActivationConfig Activation { get; } = new ActivationConfig();
|
||||
}
|
||||
public SignUpConfig SignUp { get; } = new SignUpConfig();
|
||||
public class SignInConfig
|
||||
{
|
||||
public class PasswordRequestConfig
|
||||
{
|
||||
public int EmailLinkExpiresMins = Sbm.Config.Security.Activation.EmailLinkExpiresMins_Default;
|
||||
}
|
||||
public PasswordRequestConfig PasswordRequest { get; } = new PasswordRequestConfig();
|
||||
public class KeepLoggedInConfig
|
||||
{
|
||||
public bool Allowed { get; set; } = Sbm.Config.Security.SignIn.KeepLoggedIn.Allowed_Default;
|
||||
public int CookieExpiresDays { get; set; } = Sbm.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Default;
|
||||
}
|
||||
public KeepLoggedInConfig KeepLoggedIn { get; } = new KeepLoggedInConfig();
|
||||
}
|
||||
public SignInConfig SignIn { get; } = new SignInConfig();
|
||||
}
|
||||
public SecurityConfig Security { get; } = new SecurityConfig();
|
||||
// Email.
|
||||
public class EmailConfig
|
||||
{
|
||||
public class SpecificEmailConfig
|
||||
{
|
||||
public List<String> AddressesTo { get; } = new List<string>();
|
||||
public List<String> AddressesCc { get; } = new List<string>();
|
||||
public List<String> AddressesBcc { get; } = new List<string>();
|
||||
}
|
||||
public SpecificEmailConfig ContactUs { get; } = new SpecificEmailConfig();
|
||||
public SpecificEmailConfig Signup_Activate { get; } = new SpecificEmailConfig();
|
||||
public SpecificEmailConfig Signup_Welcome { get; } = new SpecificEmailConfig();
|
||||
public String Context { get; internal set; }
|
||||
}
|
||||
public EmailConfig Email { get; } = new EmailConfig();
|
||||
// Databases.
|
||||
public class DatabaseConfig
|
||||
{
|
||||
public String Location { get; internal set; }
|
||||
public String User { get; internal set; }
|
||||
public String Password { get; internal set; }
|
||||
}
|
||||
public DatabaseConfig BusMgrDatabase { get; } = new DatabaseConfig();
|
||||
// Documents.
|
||||
public class DocumentsConfig
|
||||
{
|
||||
public String RootFolder { get; internal set; }
|
||||
}
|
||||
public DocumentsConfig Documents { get; } = new DocumentsConfig();
|
||||
// Logging.
|
||||
public class LoggingConfig
|
||||
{
|
||||
public String RootFolder { get; internal set; }
|
||||
}
|
||||
public LoggingConfig Logging { get; } = new LoggingConfig();
|
||||
|
||||
//---------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmSessionContext_Web : SbmSessionContext
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Blank construction - used for deserilisation of session data.</summary>
|
||||
protected SbmSessionContext_Web(Sbm.Application application) : base(0, application) { }
|
||||
public SbmSessionContext_Web(ushort sesionContextIndex, Sbm.Application application) :
|
||||
base(sesionContextIndex, application)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.Security;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SbmSessionData_Web : SbmSessionData
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Private construction - for JSON deserialisation.
|
||||
protected SbmSessionData_Web(long sessionIdx, int itemIdx, SbmSessionContext sessionContext) :
|
||||
base(sessionIdx, itemIdx, sessionContext)
|
||||
{
|
||||
}
|
||||
// Protected construction.
|
||||
protected SbmSessionData_Web(SbmSessionContext sessionContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser) :
|
||||
base(sessionContext, securityItemUser, affiliateUser)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// User Context.
|
||||
public SbmUserContext UserContext
|
||||
{
|
||||
get
|
||||
{
|
||||
SbmUserContext userContext = new SbmUserContext_Web(SessionContext);
|
||||
return userContext;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc.Razor;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.Middleware;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmStartup_Web
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
// Localisation.
|
||||
private static RequestCulture defaultRequestCulture = new RequestCulture("en-GB", "en-GB");
|
||||
private static List<CultureInfo> supportedCultures = new List<CultureInfo>
|
||||
{
|
||||
new CultureInfo("en-GB"),
|
||||
new CultureInfo("en-US"),
|
||||
new CultureInfo("en"),
|
||||
new CultureInfo("fr-FR"),
|
||||
new CultureInfo("fr"),
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SbmStartup_Web(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public IConfiguration Configuration { get; }
|
||||
public static RequestCulture DefaultRequestCulture { get { return defaultRequestCulture; } }
|
||||
public static List<CultureInfo> SupportedCultures { get { return new List<CultureInfo>(supportedCultures); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
protected class ConfigureServicesConfig
|
||||
{
|
||||
public IServiceCollection services;
|
||||
public String sessionCookieName;
|
||||
public bool sessionCookieHttpOnly;
|
||||
public TimeSpan sessionIdleTimeout;
|
||||
}
|
||||
protected void ConfigureServices(ConfigureServicesConfig config)
|
||||
{
|
||||
// Authentication service.
|
||||
// Required to handle 'Forbidden' responses etc.
|
||||
config.services
|
||||
.AddAuthentication(options => {
|
||||
options.DefaultAuthenticateScheme = "forbidScheme";
|
||||
options.DefaultForbidScheme = "forbidScheme";
|
||||
options.AddScheme<SbmAuthenticationHandler>("forbidScheme", "Handle Forbidden");
|
||||
});
|
||||
|
||||
// Added to support memory caching of sessions.
|
||||
config.services.AddMemoryCache();
|
||||
//config.services.AddDistributedMemoryCache(); - for multiple web servers.
|
||||
// Online web application cookie definition.
|
||||
config.services.AddSession
|
||||
(options =>
|
||||
{
|
||||
options.Cookie.Name = config.sessionCookieName;
|
||||
options.Cookie.HttpOnly = config.sessionCookieHttpOnly;
|
||||
options.IdleTimeout = config.sessionIdleTimeout;
|
||||
// Override cookie policy for session cookie. Ref. config.app.UseCookiePolicy()
|
||||
options.Cookie.IsEssential = true;
|
||||
}
|
||||
);
|
||||
|
||||
// Localisation properties folder.
|
||||
String resourcesPath = "Localisation";
|
||||
config.services.AddLocalization(opts => { opts.ResourcesPath = resourcesPath; });
|
||||
|
||||
// Modify pages during debug.
|
||||
#if DEBUG
|
||||
if (SbmSystem.DebugMode)
|
||||
// If the following line throws an error such as:
|
||||
// 'imvcbuilder' does not contain a definition for 'addrazorruntimecompilation'
|
||||
// Revert the NuGet Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package
|
||||
// to a previous version and then reinstal the latest version.
|
||||
config.services.AddRazorPages().AddRazorRuntimeCompilation();
|
||||
#endif
|
||||
|
||||
config.services.AddMvc
|
||||
(options =>
|
||||
{
|
||||
// Model binding - intercepting form values being bound to models.
|
||||
options.ModelBinderProviders.Insert(0, new SbmModelBinderProvider());
|
||||
// Blank form values to be populated to model as empty strings rather than null values.
|
||||
options.ModelMetadataDetailsProviders.Add(new SbmMetadataProvider());
|
||||
}
|
||||
)
|
||||
// View and data annotation localisations.
|
||||
.AddViewLocalization(
|
||||
LanguageViewLocationExpanderFormat.Suffix,
|
||||
opts => { opts.ResourcesPath = resourcesPath; })
|
||||
.AddDataAnnotationsLocalization();
|
||||
|
||||
// Configure localisation middleware.
|
||||
config.services.Configure<RequestLocalizationOptions>
|
||||
(opts =>
|
||||
{
|
||||
// Default culture to use for requests.
|
||||
opts.DefaultRequestCulture = DefaultRequestCulture;
|
||||
// Cultures supported by the application. Formatting numbers, dates, etc.
|
||||
opts.SupportedCultures = SupportedCultures;
|
||||
// UI cultures supported by the application. UI strings that have been localized.
|
||||
opts.SupportedUICultures = SupportedCultures;
|
||||
}
|
||||
);
|
||||
|
||||
// Allows access to the HttpContext inside a service.
|
||||
config.services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
protected class ConfigureConfig
|
||||
{
|
||||
public IApplicationBuilder app;
|
||||
public IHostApplicationLifetime hostApplicationLifetime;
|
||||
public IWebHostEnvironment env;
|
||||
}
|
||||
protected void Configure(ConfigureConfig config)
|
||||
{
|
||||
if (config.env.IsDevelopment())
|
||||
{
|
||||
config.app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
config.app.UseExceptionHandler("/Home/Error");
|
||||
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
|
||||
config.app.UseHsts();
|
||||
}
|
||||
|
||||
config.app.UseHttpsRedirection();
|
||||
config.app.UseStaticFiles();
|
||||
config.app.UseCookiePolicy();
|
||||
config.app.UseSession();
|
||||
config.app.UseRouting();
|
||||
//config.app.UseAuthorization();
|
||||
config.app.UseAntiforgeryTokens();
|
||||
|
||||
config.app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapControllerRoute(
|
||||
name: "default",
|
||||
pattern: "{controller=Home}/{action=Index}/{id?}");
|
||||
});
|
||||
|
||||
// Application events.
|
||||
// NB The shutdown events only fire if he application stops 'gracefully'.
|
||||
config.hostApplicationLifetime.ApplicationStarted.Register(OnApplicationStarted);
|
||||
config.hostApplicationLifetime.ApplicationStopping.Register(OnApplicationStopping);
|
||||
config.hostApplicationLifetime.ApplicationStopped.Register(OnApplicationStopped);
|
||||
|
||||
config.app.Use(async (context, next) =>
|
||||
{
|
||||
if (context.Request.Method.Equals(HttpMethod.Get.Method))
|
||||
{
|
||||
context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue()
|
||||
{
|
||||
Public = true,
|
||||
MaxAge = TimeSpan.FromSeconds(10)
|
||||
};
|
||||
//context.Response.Headers[HeaderNames.Vary] = new string[] { "Accept-Encoding" };
|
||||
}
|
||||
await next();
|
||||
});
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application events.
|
||||
private readonly static String ApplicationEventLogPrefix = "### ";
|
||||
private void OnApplicationStarted()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application started");
|
||||
}
|
||||
private void OnApplicationStopping()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application stopping");
|
||||
}
|
||||
private void OnApplicationStopped()
|
||||
{
|
||||
SaLogger.Info(ApplicationEventLogPrefix + "Application stopped");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
using Sarand.BusinessMgr.Net.Standard.Dbas.App;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmSystem_Web : SbmSystem_Dbas
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Static initialisation.</summary>
|
||||
static SbmSystem_Web()
|
||||
{
|
||||
InitComputerName();
|
||||
InitUserName();
|
||||
InitApplicationPath();
|
||||
InitApplicationFolder();
|
||||
InitAssemblyBuildAt();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SbmSystem_Web(PropertySet properties) : base(properties)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Computer name
|
||||
/// <para>Windows: System.Environment.MachineName</para>
|
||||
/// <para>Web: HttpContext.Current.Server.MachineName</para>
|
||||
/// <para>FQDN: System.Net.Dns.GetHostName()</para>
|
||||
/// </summary>
|
||||
private static void InitComputerName()
|
||||
{
|
||||
try
|
||||
{
|
||||
ComputerName = System.Environment.MachineName;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitComputerName Failed to initialise computer name from environment. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
try
|
||||
{
|
||||
if (StringUtil.IsEmpty(ComputerName))
|
||||
ComputerName = Environment.GetEnvironmentVariable("CUMPUTERNAME") ?? Environment.GetEnvironmentVariable("HOSTNAME");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitComputerName Failed to initialise computer name from environment variable. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>To be populated by application<para>Windows: Environment.UserName</para></summary>
|
||||
private static void InitUserName()
|
||||
{
|
||||
try
|
||||
{
|
||||
UserName = Environment.UserName;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitUserName Failed to initialise user name. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Application Path.
|
||||
/// <para>Windows: System.Reflection.Assembly.GetEntryAssembly().Location;</para>
|
||||
/// </summary>
|
||||
private static void InitApplicationPath()
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationPath = Assembly.GetEntryAssembly().Location;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitApplicationPath Failed to initialise application path. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Application folder.
|
||||
/// <para>Windows: System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);</para>
|
||||
/// </summary>
|
||||
private static void InitApplicationFolder()
|
||||
{
|
||||
try
|
||||
{
|
||||
ApplicationFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitApplicationFolder Failed to initialise application folder. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// DateTime when the executing assembly was built.
|
||||
/// </summary>
|
||||
private static void InitAssemblyBuildAt()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Assembly build date.
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
AssemblyBuildAt = File.GetLastWriteTime(assembly.Location);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn("SbmSystem.InitAssemblyBuildAt Failed to initialise assembly build date. " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.App
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmUserContext_Web : SbmUserContext
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data memebrs.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SbmUserContext_Web(SbmSessionContext sessionContext) : base(sessionContext)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Consoles
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmEmailConsole_Web : SbmEmailConsole
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
public SbmEmailConsole_Web(SbmEmailConfig emailConfig) :
|
||||
base(emailConfig)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,523 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.App;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.Models;
|
||||
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.Mgr;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.CodeTypes;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Diary;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Interfaces;
|
||||
using Sarand.Net.Standard.Base.ItemData;
|
||||
using Sarand.Net.Standard.Base.ItemDocs;
|
||||
using Sarand.Net.Standard.Base.ItemOptions;
|
||||
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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Controllers
|
||||
{
|
||||
//=======================================================================
|
||||
public abstract class SbmController_Base : Controller
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SbmInternals internals;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SbmController_Base(SbmLocaliser localiser)
|
||||
{
|
||||
Localiser = localiser;
|
||||
|
||||
// Initialise console (debug) logging listener.
|
||||
//if (Directory.Exists(App.LoggingRootFolder) && SbmSystem.DebugMode)
|
||||
// SbmConsoleListener.ConfigureDebugListener(App.LoggingRootFolder);
|
||||
if (DebugMode) SaLogger.Trace(GetType().Name + ".CTR");
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public bool DebugMode { get; } = SacsSystem.DebugMode;
|
||||
protected SbmApplication_Web App { get { return SbmApplication_Web.WebApp; } }
|
||||
public SbmSessionConfig SessionConfig { get { return App.SessionConfig; } }
|
||||
public SbmSessionContext SessionContext { get { return App.SessionContext; } }
|
||||
public SbmUserContext UserContext { get { return SessionData.UserContext; } }
|
||||
protected SbmLocaliser Localiser { get; }
|
||||
/// <summary>
|
||||
/// Indicate whether session data should be stored by action.
|
||||
/// <para>Any action that might modify the session data must store it.</para>
|
||||
/// <para>Some actions such as scoring a password's complexity don't need to.</para>
|
||||
/// </summary>
|
||||
public virtual bool StoreSessionData { get; protected set; } = true;
|
||||
// Culture.
|
||||
private string LanguageIso2
|
||||
{
|
||||
get
|
||||
{
|
||||
var feature = HttpContext.Features.Get<IRequestCultureFeature>();
|
||||
return feature.RequestCulture.UICulture.TwoLetterISOLanguageName.ToLower();
|
||||
}
|
||||
}
|
||||
// Business components.
|
||||
public SbmInternals Internals { get { if (internals == null) internals = new SbmInternals(UserContext); return internals; } }
|
||||
// Managers.
|
||||
public SbmAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
|
||||
public SbmAssetMgr AssetMgr { get { return Internals.AssetMgr; } }
|
||||
public SbmCommodityMgr CommodityMgr { get { return Internals.CommodityMgr; } }
|
||||
public SbmPriceMgr PriceMgr { get { return Internals.PriceMgr; } }
|
||||
public SbmTransactionMgr TransactionMgr { get { return Internals.TransactionMgr; } }
|
||||
public SbmStockMgr StockMgr { get { return Internals.StockMgr; } }
|
||||
public SbmProcessMgr ProcessMgr { get { return Internals.ProcessMgr; } }
|
||||
public SbmDataItemMgr DataItemMgr { get { return Internals.DataItemMgr; } }
|
||||
// Consoles.
|
||||
public SbmConfigConsole ConfigConsole { get { return Internals.ConfigConsole; } }
|
||||
public SaDiaryConsole DiaryConsole { get { return Internals.DiaryConsole; } }
|
||||
public SaSecurityConsole SecurityConsole { get { return Internals.SecurityConsole; } }
|
||||
public SaCodeTypeConsole CodeTypeConsole { get { return Internals.CodeTypeConsole; } }
|
||||
public SaReferenceDataConsole ReferenceDataConsole { get { return Internals.ReferenceDataConsole; } }
|
||||
public SaUpdateLogConsole UpdateLogConsole { get { return Internals.UpdateLogConsole; } }
|
||||
public SaInterfaceConsole InterfaceConsole { get { return Internals.InterfaceConsole; } }
|
||||
public SaItemDocConsole ItemDocConsole { get { return Internals.ItemDocConsole; } }
|
||||
public SaItemOptionConsole ItemOptionConsole { get { return Internals.ItemOptionConsole; } }
|
||||
public SaItemDataConsole ItemDataConsole { get { return Internals.ItemDataConsole; } }
|
||||
// Configurations.
|
||||
public SbmStockControlConfig StockControlConfig { get { return Internals.StockControlConfig; } }
|
||||
public SbmRequirementCostingConfig RequirementCostingConfig { get { return Internals.RequirementCostingConfig; } }
|
||||
// System codes.
|
||||
public List<TypeCodeDesc> GetCodesOfType(Sbm.SystemCode systemCode) { return Internals.GetCodesOfType(systemCode); }
|
||||
// Email.
|
||||
public SaEmailConfig EmailConfig { get { return Internals.EmailConfig; } }
|
||||
public SbmEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
//-------------------------------------------------------------------
|
||||
public static readonly String ParamName_SessionExpired = "SessionExpired";
|
||||
protected enum RedirectLocation
|
||||
{
|
||||
WebAppBase,
|
||||
WebAppHome,
|
||||
WebAppHome_SessionExpired,
|
||||
}
|
||||
protected String GetRedirectLocation(RedirectLocation redirectLocation)
|
||||
{
|
||||
string protocol = Request.Scheme;
|
||||
var parameters = new RouteValueDictionary();
|
||||
String homeAction = Url.Action("Index", "Home", parameters, protocol);
|
||||
switch (redirectLocation)
|
||||
{
|
||||
case RedirectLocation.WebAppBase:
|
||||
return Regex.Replace(homeAction, "\\/$", "") + "/";
|
||||
case RedirectLocation.WebAppHome:
|
||||
return homeAction;
|
||||
case RedirectLocation.WebAppHome_SessionExpired:
|
||||
// Set the session expired parameter so that the page can report it.
|
||||
// NB Paramater must have a value to be included in the URL query string.
|
||||
parameters.Add(ParamName_SessionExpired, "1");
|
||||
return homeAction;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Action execution events.
|
||||
//-------------------------------------------------------------------
|
||||
public override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||
{
|
||||
if (DebugMode) SaLogger.Debug(GetType().Name + ".OnActionExecuting" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
// Refreh model properties.
|
||||
SbmModel_Base baseModel = ViewData.Model as SbmModel_Base;
|
||||
RefreshModel(baseModel);
|
||||
|
||||
base.OnActionExecuting(filterContext);
|
||||
}
|
||||
public override void OnActionExecuted(ActionExecutedContext filterContext)
|
||||
{
|
||||
if (DebugMode) SaLogger.Debug(GetType().Name + ".OnActionExecuted" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
// Refreh model properties.
|
||||
SbmModel_Base baseModel = ViewData.Model as SbmModel_Base;
|
||||
RefreshModel(baseModel);
|
||||
|
||||
// Store session data if present - as potentially modfied.
|
||||
if (SessionData != null)
|
||||
{
|
||||
// Most actions will store the session data in case it's been modified.
|
||||
// Some actions (eg. score password) don't need to.
|
||||
if (StoreSessionData)
|
||||
{
|
||||
String sessionDataJson = JsonConvert.SerializeObject(SessionData);
|
||||
HttpContext.Session.Set(SessionStorage.SessionKey_SessionConfig, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson));
|
||||
}
|
||||
}
|
||||
else HttpContext.Session.Remove(SessionStorage.SessionKey_SessionConfig);
|
||||
|
||||
// Response headers.
|
||||
if (baseModel != null && baseModel.ProhibitCache)
|
||||
{
|
||||
if (Response.Headers.ContainsKey(HeaderNames.CacheControl))
|
||||
Response.Headers.Remove(HeaderNames.CacheControl);
|
||||
Response.Headers.Add(HeaderNames.CacheControl, "no-cache, no-store, must-revalidate");
|
||||
Response.Headers.Add(HeaderNames.Pragma, "no-cache");
|
||||
Response.Headers.Add(HeaderNames.Expires, "0");
|
||||
}
|
||||
|
||||
|
||||
base.OnActionExecuted(filterContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Model.
|
||||
//-------------------------------------------------------------------
|
||||
protected void RefreshModel(SbmModel_Base model)
|
||||
{
|
||||
if (model == null) return;
|
||||
|
||||
// Session data.
|
||||
model.SessionData_Web = SessionData;
|
||||
|
||||
// Redirect locations.
|
||||
model.RedirectLocation.Base = GetRedirectLocation(RedirectLocation.WebAppBase);
|
||||
model.RedirectLocation.Home = GetRedirectLocation(RedirectLocation.WebAppHome);
|
||||
model.RedirectLocation.Home_SessionExpired = GetRedirectLocation(RedirectLocation.WebAppHome_SessionExpired);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Parameters.
|
||||
//-------------------------------------------------------------------
|
||||
public String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = nameof(ControllerBase) + ".EncryptParameters";
|
||||
try
|
||||
{
|
||||
// Copy the list of parameters, adding a random name/value pair to randomise the encryption.
|
||||
NameValueCollection parametersToEncrypt = new NameValueCollection(parameters);
|
||||
// NB Range 10-189 intended to have equal chance of 2 or 3 digit number.
|
||||
parametersToEncrypt.Add("!" + SacsRandomHelper.GetInt32(10, 190).ToString(), SacsRandomHelper.GetInt32(10, 190).ToString());
|
||||
|
||||
// Sort the keys to ensure that the random '!' param is first in the query string.
|
||||
String[] paramKeys = parametersToEncrypt.AllKeys;
|
||||
Array.Sort(paramKeys);
|
||||
|
||||
// Serialise parameters as if in a URL query string - so that they can be deserialised in DecryptParameters() below.
|
||||
string queryString = String.Join("&", paramKeys.Select(a => a + "=" + HttpUtility.UrlEncode(parametersToEncrypt[a])));
|
||||
String encrypted = SacsEncryptionHelper.Encrypt(queryString, base64IV, base64Key);
|
||||
if (DebugMode)
|
||||
{
|
||||
SaLogger.Debug(fn + " Encrypted: " + encrypted);
|
||||
NameValueCollection decryptedParams = DecryptParameters(encrypted, base64IV, base64Key);
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return "";
|
||||
}
|
||||
public NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = nameof(ControllerBase) + ".DecryptParameters";
|
||||
if (DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tIV: " + base64IV + "\n\tKey: " + base64Key);
|
||||
try
|
||||
{
|
||||
String queryString = SacsEncryptionHelper.Decrypt(encrypted, base64IV, base64Key);
|
||||
return HttpUtility.ParseQueryString(queryString);
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return new NameValueCollection();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cookies.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve the value from the named request cookie.</summary>
|
||||
public String GetRequestCookie(String key)
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(key))
|
||||
return Request.Cookies[key];
|
||||
return null;
|
||||
}
|
||||
/// <summary>Set the value against the named response cookie.</summary>
|
||||
public void SetResponseCookie(string key, string value, DateTime? expiresAt = null, bool isEssential = false)
|
||||
{
|
||||
CookieOptions options = new CookieOptions();
|
||||
options.HttpOnly = true;
|
||||
options.Secure = true;
|
||||
options.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
|
||||
if (expiresAt.HasValue)
|
||||
options.Expires = expiresAt;
|
||||
if (isEssential)
|
||||
options.IsEssential = true;
|
||||
Response.Cookies.Append(key, value, options);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session.
|
||||
//-------------------------------------------------------------------
|
||||
public bool ValidUserSession { get { return SessionData?.ValidUserSession ?? false; } }
|
||||
public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SbmSystem.ComputerName); } }
|
||||
// Referrer.
|
||||
public String Referer { get { return Request.Headers["Referer"].ToString(); } }
|
||||
public bool ValidReferer { get { return !StringUtil.IsEmpty(Referer); } }
|
||||
/// <summary>Store session data, eg. to start a new user session on sign-in.</summary>
|
||||
protected bool SetSessionData(SbmSessionData_Web sessionData)
|
||||
{
|
||||
if (sessionStorage.SessionData != null) return false;
|
||||
sessionStorage.SessionData = sessionData;
|
||||
return true;
|
||||
}
|
||||
protected void ClearSessionData()
|
||||
{
|
||||
if (HttpContext.Session.IsAvailable)
|
||||
HttpContext.Session.Clear();
|
||||
sessionStorage.SessionData = null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Session storage.
|
||||
public class SessionStorage
|
||||
{
|
||||
public SbmSessionData_Web SessionData { get; set; }
|
||||
public static String SessionKey_SessionConfig { get; } = "SbmSessionData";
|
||||
public static Encoding sessionDataEncoding { get; } = Encoding.UTF8;
|
||||
//JSON Serialisation.
|
||||
public class SbmSessionDataContractResolver : DefaultContractResolver
|
||||
{
|
||||
// To allow private properties to be deserialised.
|
||||
// NB Only applies to top level properties in the serialised object.
|
||||
protected override List<MemberInfo> GetSerializableMembers(Type objectType)
|
||||
{
|
||||
var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
MemberInfo[] fields = objectType.GetFields(flags);
|
||||
return fields
|
||||
.Concat(objectType.GetProperties(flags).Where(propInfo => propInfo.CanWrite))
|
||||
.ToList();
|
||||
}
|
||||
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
|
||||
{
|
||||
return base.CreateProperties(type, MemberSerialization.Fields);
|
||||
}
|
||||
};
|
||||
public static JsonSerializerSettings JsonDeserialisationSettings = new JsonSerializerSettings
|
||||
{
|
||||
ContractResolver = new SbmSessionDataContractResolver(),
|
||||
// Force all deserialised objects to be replaced - to avoid proxy lists not populating.
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace
|
||||
};
|
||||
}
|
||||
private readonly SessionStorage sessionStorage = new SessionStorage();
|
||||
protected JsonSerializerSettings SbmSessionDataJsonSerializerSettings { get { return SessionStorage.JsonDeserialisationSettings; } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SbmSessionData_Web SessionData
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
// Retrieve session data if not already in controller.
|
||||
if (sessionStorage.SessionData == null)
|
||||
{
|
||||
byte[] sessionDataBytes = null;
|
||||
HttpContext.Session.TryGetValue(SessionStorage.SessionKey_SessionConfig, out sessionDataBytes);
|
||||
if (sessionDataBytes != null)
|
||||
{
|
||||
String sessionDataJson = SessionStorage.sessionDataEncoding.GetString(sessionDataBytes);
|
||||
sessionStorage.SessionData = DeserializeSessionData(sessionDataJson);
|
||||
}
|
||||
}
|
||||
return sessionStorage.SessionData;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(GetType().Name + ".SessionData " + exc.GetType().Name + " - " + exc.Message + exc.GetStackEntries().Concat("", "\n\t"));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
protected abstract SbmSessionData_Web DeserializeSessionData(String sessionDataJson);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax actions.
|
||||
//-------------------------------------------------------------------
|
||||
protected static readonly Encoding ajaxResponseEncoding = Encoding.UTF8;
|
||||
protected IActionResult GetAjaxResult_GoHome(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
protected IActionResult GetAjaxResult_InvalidSession(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class AjaxResponse_Base
|
||||
{
|
||||
// Response status.
|
||||
public bool Success { get; set; } = false;
|
||||
public bool Error { get; set; } = false;
|
||||
public bool SessionExpired { get; protected set; } = false;
|
||||
public bool GoHome { get; protected set; } = false;
|
||||
public AjaxResponse_Base SetSessionExpired(String title, String text)
|
||||
{
|
||||
SessionExpired = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome()
|
||||
{
|
||||
GoHome = true;
|
||||
return this;
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome(String title, String text)
|
||||
{
|
||||
GoHome = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
// Message - displays alert popup.
|
||||
public class MessageData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Text { get; set; }
|
||||
}
|
||||
public MessageData Message { get; private set; }
|
||||
public AjaxResponse_Base SetMessage(String title, String text)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
Message = new MessageData() { Title = title, Text = text };
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class AjaxResponse_Data : AjaxResponse_Base
|
||||
{
|
||||
// Construction.
|
||||
protected AjaxResponse_Data(SbmModel_Base model)
|
||||
{
|
||||
}
|
||||
// Form data.
|
||||
public class FormControlValue
|
||||
{
|
||||
public FormControlValue(String controlName, String value, String error)
|
||||
{
|
||||
ControlName = controlName;
|
||||
Value = value;
|
||||
Error = error;
|
||||
}
|
||||
public String ControlName { get; }
|
||||
public String Value { get; set; }
|
||||
public String Error { get; set; }
|
||||
}
|
||||
private readonly Dictionary<String, FormControlValue> controlValues = new Dictionary<String, FormControlValue>();
|
||||
public List<FormControlValue> ControlValues { get { return controlValues.Values.ToList(); } }
|
||||
public void SetControlValue(String controlName, String value, String error = null)
|
||||
{
|
||||
if (controlValues.ContainsKey(controlName))
|
||||
{
|
||||
// Modify existing entry in the list.
|
||||
FormControlValue controlValue = controlValues[controlName];
|
||||
if (value != null) controlValue.Value = value;
|
||||
if (error != null) controlValue.Error = error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new control to list.
|
||||
controlValues.Add(controlName, new FormControlValue(controlName, value, error));
|
||||
}
|
||||
}
|
||||
/// <summary>Assign the error to the control by name and return this response data.</summary>
|
||||
public AjaxResponse_Data SetControlError(String controlName, String error)
|
||||
{
|
||||
return SetControlError(controlName, error, this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Assign the error to the control by name and return the specified value.
|
||||
/// <para>- Allows alternative return values to be specified (eg. 'false') to avoid separate return statement in calling routine.</para>
|
||||
/// </summary>
|
||||
public T SetControlError<T>(String controlName, String error, T returnValue)
|
||||
{
|
||||
SetControlValue(controlName, null, error);
|
||||
return returnValue;
|
||||
}
|
||||
public bool HasControlErrors()
|
||||
{
|
||||
foreach (FormControlValue controlValue in controlValues.Values)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(controlValue.Error)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Notification - briefly displays after response received.
|
||||
public class NotificationData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Message { get; set; }
|
||||
}
|
||||
public NotificationData Notification { get; private set; }
|
||||
public bool HasNotification { get { return Notification != null; } }
|
||||
public AjaxResponse_Data SetNotification(String title, String message)
|
||||
{
|
||||
Notification = new NotificationData() { Title = title, Message = message };
|
||||
return this;
|
||||
}
|
||||
// Paged data.
|
||||
public class PagingData
|
||||
{
|
||||
public PagingData(SbmModel_Base model) :
|
||||
this(model.Paging.PageNo, model.Paging.PageLength, model.Paging.ItemCount, model.Paging.ItemTotal)
|
||||
{ }
|
||||
public PagingData(uint pageNo, ushort pageLength, ushort itemCount, ulong itemTotal)
|
||||
{
|
||||
PageNo = pageNo;
|
||||
PageLength = pageLength;
|
||||
ItemCount = itemCount;
|
||||
ItemTotal = itemTotal;
|
||||
}
|
||||
public bool Paged { get { return (PageNo > 0 && PageLength > 0 && ItemTotal > PageLength); } }
|
||||
public uint PageNo { get; } = 0;
|
||||
public ushort PageLength { get; } = 0;
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / PageLength) : 0); } }
|
||||
public ushort ItemCount { get; } = 0;
|
||||
public ulong ItemTotal { get; } = 0;
|
||||
}
|
||||
public PagingData Paging { get; private set; }
|
||||
public void SetPaging(SbmModel_Base model)
|
||||
{
|
||||
Paging = new PagingData(model);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.App;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
|
||||
using Sarand.Net.Standard.Base.Email;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SbmEmailConfigHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Extract the email configurations from the application settings.</summary>
|
||||
public static Dictionary<String, SbmEmailConfig> ExtractEmailConfigs(IConfigurationSection emailConfigsSection)
|
||||
{
|
||||
Dictionary<String, SbmEmailConfig> emailConfigs = new Dictionary<String, SbmEmailConfig>();
|
||||
foreach (ConfigurationSection emailConfigSection in emailConfigsSection.GetChildren())
|
||||
{
|
||||
if (!StringUtil.IsEmpty(emailConfigSection.Key))
|
||||
emailConfigs.Add(emailConfigSection.Key, CreateEmailConfig(emailConfigSection.Key, emailConfigSection));
|
||||
}
|
||||
return emailConfigs;
|
||||
}
|
||||
private static SbmEmailConfig CreateEmailConfig(String context, ConfigurationSection emailConfigSection)
|
||||
{
|
||||
SbmEmailConfig emailConfig = new SbmEmailConfig(context);
|
||||
if (emailConfigSection != null)
|
||||
{
|
||||
IConfigurationSection message = emailConfigSection.GetSection("Message");
|
||||
emailConfig.Message.AddressFrom = message["AddressFrom"];
|
||||
foreach (var addressBcc in message.GetSection("AddressesBcc").GetChildren())
|
||||
emailConfig.Message.AddressesBcc.Add(StringUtil.TrimAll(addressBcc.Value));
|
||||
IConfigurationSection smtp = emailConfigSection.GetSection("SMTP");
|
||||
emailConfig.SMTP.Server = smtp["Server"];
|
||||
emailConfig.SMTP.ServerPort = StringUtil.ToInt(smtp["ServerPort"]);
|
||||
emailConfig.SMTP.UseSSL = StringUtil.ToBool(smtp["UseSSL"]);
|
||||
IConfigurationSection send = emailConfigSection.GetSection("Send");
|
||||
emailConfig.Send.Using = send["Using"];
|
||||
emailConfig.Send.UserName = send["UserName"];
|
||||
emailConfig.Send.Password = send["Password"];
|
||||
}
|
||||
return emailConfig;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Send email.
|
||||
public static bool SendEmail(SaEmailData emailData)
|
||||
{
|
||||
// ToDo return EmailConsole.SendEmail(emailData);
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Replace dynamic tags in email message body.
|
||||
/// <para></para>
|
||||
/// </summary>
|
||||
public static void ReplaceDynamicEmailBodyTags(SaEmailData emailData, SbmSessionData sessionData, SbmAffiliate affiliateUser)
|
||||
{
|
||||
// Replace core tags, eg. main stylesheet.
|
||||
// ToDo. EmailConsole.ReplaceDynamicEmailTags(emailData);
|
||||
|
||||
// Replace tags known to the web application.
|
||||
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public static class EmailConfigList
|
||||
{
|
||||
public static SbmEmailConfig getConfigForSession(this List<SbmEmailConfig> emailConfigs, SbmSessionConfig sessionConfig)
|
||||
{
|
||||
if (sessionConfig != null && !StringUtil.IsEmpty(sessionConfig.Email.Context))
|
||||
{
|
||||
foreach (SbmEmailConfig emailConfig in emailConfigs)
|
||||
{
|
||||
if (emailConfig.Context.EqualsCI(sessionConfig.Email.Context))
|
||||
return emailConfig;
|
||||
}
|
||||
}
|
||||
return new SbmEmailConfig("");
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.App;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Helpers
|
||||
{
|
||||
//=======================================================================
|
||||
public static class SbmSessionConfigHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
public static Dictionary<String, SbmSessionConfig> ExtractSessionConfigs(IConfigurationSection sessionConfigsSection)
|
||||
{
|
||||
// NB The set of configurations will only allow one per context.
|
||||
// Only the last configuration found for each context will be stored (NB usually only one of each apart from 'Defaults').
|
||||
Dictionary<String, SbmSessionConfig> sessionConfigs = new Dictionary<String, SbmSessionConfig>();
|
||||
|
||||
// Start the list with a default 'Defaults' configuration - values set to application defaults (defined in Sbm).
|
||||
// NB This can be overridden in each level of configuration.
|
||||
// Settings from the 'Defaults' configuration provide values where they are missing from other configurations.
|
||||
// NB Coverage may not be 100% - just where it's proven needed.
|
||||
SbmSessionConfig defaultsSessionConfig = new SbmSessionConfig(Sbm.Config.Context_Defaults, null, null);
|
||||
sessionConfigs.Add(defaultsSessionConfig.Context, defaultsSessionConfig);
|
||||
|
||||
// Load session configurations.
|
||||
foreach (ConfigurationSection sessionConfigSection in sessionConfigsSection.GetChildren())
|
||||
{
|
||||
if (StringUtil.IsEmpty(sessionConfigSection.Key)) continue;
|
||||
|
||||
// Extract the configuration, supplying current 'Defaults' to supply missing values, and add to the list.
|
||||
SbmSessionConfig sessionConfig = new SbmSessionConfig(sessionConfigSection.Key, sessionConfigSection, defaultsSessionConfig);
|
||||
sessionConfigs.Remove(sessionConfigSection.Key);
|
||||
sessionConfigs.Add(sessionConfigSection.Key, sessionConfig);
|
||||
|
||||
// Replace the 'Defaults' configuration if this one matches the context.
|
||||
if (sessionConfig.Context.EqualsCI(Sbm.Config.Context_Defaults))
|
||||
defaultsSessionConfig = sessionConfig;
|
||||
}
|
||||
return sessionConfigs;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public static class SessionConfigList
|
||||
{
|
||||
public static SbmSessionConfig getConfigForApplication(this List<SbmSessionConfig> sessionConfigs)
|
||||
{
|
||||
SbmSessionConfig defaultsSessionConfig = new SbmSessionConfig("", null, null);
|
||||
SbmApplication app = SbmGlobals.Application;
|
||||
if (app != null)
|
||||
{
|
||||
foreach (SbmSessionConfig sessionConfig in sessionConfigs)
|
||||
{
|
||||
if (sessionConfig.Environments.ContainsCI(app.EnvironmentName))
|
||||
return sessionConfig;
|
||||
if (sessionConfig.Context.EqualsCI(Sbm.Config.Context_Defaults))
|
||||
defaultsSessionConfig = sessionConfig;
|
||||
}
|
||||
}
|
||||
return defaultsSessionConfig;
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
// Authentication handler required to allow actions to issue Forbid() responses.
|
||||
// Ref. https://stackoverflow.com/questions/54578426/why-do-i-need-to-set-a-defaultforbidscheme/54587054#54587054
|
||||
//=======================================================================
|
||||
public class SbmAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public SbmAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) :
|
||||
base(options, logger, encoder, clock)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected override Task HandleForbiddenAsync(AuthenticationProperties properties)
|
||||
{
|
||||
Context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
return base.HandleForbiddenAsync(properties);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
Context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
|
||||
return AuthenticateResult.NoResult();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Force blank form values to be populated to the model as empty strings rather than null values.
|
||||
/// </summary>
|
||||
public class SbmMetadataProvider : IMetadataDetailsProvider, IDisplayMetadataProvider
|
||||
{
|
||||
public void CreateDisplayMetadata(DisplayMetadataProviderContext context)
|
||||
{
|
||||
if (context.Key.MetadataKind == ModelMetadataKind.Property)
|
||||
{
|
||||
context.DisplayMetadata.ConvertEmptyStringToNull = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Maps a browser request to a data object. Default class provides a base implementation of a model binder.
|
||||
/// <para>Overridden to trim whitespace from input values.</para>
|
||||
/// </summary>
|
||||
public class SbmModelBinder : ComplexTypeModelBinder
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SbmModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) :
|
||||
base(propertyBinders, loggerFactory)
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Creates the model with one (or more) injected service parameters.
|
||||
/// </summary>
|
||||
protected override object CreateModel(ModelBindingContext bindingContext)
|
||||
{
|
||||
var services = bindingContext.HttpContext.RequestServices;
|
||||
var modelType = bindingContext.ModelType;
|
||||
var ctors = modelType.GetConstructors();
|
||||
foreach (var ctor in ctors)
|
||||
{
|
||||
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
|
||||
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
|
||||
if (parameters.All(p => p != null))
|
||||
{
|
||||
var model = ctor.Invoke(parameters);
|
||||
return model;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Intercept String properties and trim whitespace.
|
||||
/// </summary>
|
||||
protected override void SetProperty(ModelBindingContext bindingContext, string modelName, ModelMetadata propertyMetadata, ModelBindingResult result)
|
||||
{
|
||||
string fn = GetType().Name + ".SetProperty";
|
||||
//if (SbmSystem.DebugMode) Logger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + ".");
|
||||
object originalValue = result.Model;
|
||||
// Exclude properties that retain leading/trailing whitespace.
|
||||
if (result.Model is string)
|
||||
{
|
||||
if (!modelName.ContainsCI("Password"))
|
||||
{
|
||||
string value = result.Model as string;
|
||||
|
||||
// Trim leading and trailing whitespace.
|
||||
value = StringUtil.TrimAll(value);
|
||||
|
||||
// Check for multi-line.
|
||||
if (value.Contains('\n'))
|
||||
{
|
||||
// Simplify line delimiters.
|
||||
value = Regex.Replace(value, "\\r\\n", "\n");
|
||||
// Remove white space in front of newlines.
|
||||
value = Regex.Replace(value, "\\s+\\n", "\n");
|
||||
// Remove multiple newlines.
|
||||
value = Regex.Replace(value, "\\n+", "\n");
|
||||
}
|
||||
|
||||
// Email addresses must be lowercase to ensure match to encrypted data.
|
||||
if (modelName.EqualsCI("EmailAddress") || modelName.EqualsCI("AccountEmailAddress"))
|
||||
value = value.ToLower();
|
||||
|
||||
// Uppercase selected values.
|
||||
if (modelName.EqualsCI("Postcode") || modelName.EqualsCI("AccountPostcode") || modelName.EqualsCI("RegisteredAddressPostcode"))
|
||||
value = value.ToUpper();
|
||||
|
||||
// Assign resulting value.
|
||||
result = ModelBindingResult.Success(value);
|
||||
}
|
||||
}
|
||||
if (result.Model != null && SbmSystem.DebugMode)
|
||||
SaLogger.Debug(fn + " Form property " + modelName + ": '" + result.Model.ToString() + "'." + (originalValue != null && !originalValue.Equals(result.Model) ? " Original value: '" + originalValue.ToString() + "'" : ""));
|
||||
base.SetProperty(bindingContext, modelName, propertyMetadata, result);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Maps a browser request to a data object. Default class provides a base implementation of a model binder.
|
||||
/// <para>Overridden to trim whitespace from input values.</para>
|
||||
/// </summary>
|
||||
public class SbmModelBinderProvider : IModelBinderProvider
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SbmModelBinderProvider()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public IModelBinder GetBinder(ModelBinderProviderContext context)
|
||||
{
|
||||
if (context == null) throw new ArgumentNullException(nameof(context));
|
||||
|
||||
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
|
||||
{
|
||||
var propertyBinders = context.Metadata.Properties.ToDictionary(property => property, context.CreateBinder);
|
||||
ILoggerFactory loggerFactory = (ILoggerFactory)context.Services.GetService(typeof(ILoggerFactory));
|
||||
return new SbmModelBinder(propertyBinders, loggerFactory);
|
||||
}
|
||||
|
||||
// Default - return null so that default binding provider is used.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Sarand.BusinessMgr.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Middleware
|
||||
{
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Extend IApplicationBuilder class to use the anit-forgery token validation middleware.
|
||||
/// </summary>
|
||||
public static class ApplicationBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseAntiforgeryTokens(this IApplicationBuilder app)
|
||||
{
|
||||
return app.UseMiddleware<ValidateAntiForgeryTokenMiddleware>();
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
/// <summary>
|
||||
/// Ensure relevant actions validate the anti-forgery token, eg. post requests.
|
||||
/// </summary>
|
||||
public class ValidateAntiForgeryTokenMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IAntiforgery _antiforgery;
|
||||
|
||||
public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
|
||||
{
|
||||
_next = next;
|
||||
_antiforgery = antiforgery;
|
||||
}
|
||||
|
||||
public async Task Invoke(HttpContext context)
|
||||
{
|
||||
String fn = GetType().Name + ".Invoke";
|
||||
|
||||
// Log action.
|
||||
//String rawTarget = context.Features.Get<IHttpRequestFeature>().RawTarget;
|
||||
if (SbmSystem.DebugMode) SaLogger.Debug(fn + " Action: '" + Regex.Replace(context.Request.Path.ToString(), "^/", "") + "'. Method: " + context.Request.Method);
|
||||
|
||||
// Intercept POST requests and apply anti-forgery test.
|
||||
if (HttpMethods.IsPost(context.Request.Method))
|
||||
{
|
||||
await _antiforgery.ValidateRequestAsync(context);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await _next(context);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Warn(fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
throw exc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
using Microsoft.AspNetCore.Html;
|
||||
using Microsoft.AspNetCore.Mvc.Rendering;
|
||||
using Sarand.BusinessMgr.Net.Core.Web.App;
|
||||
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.CodeTypes;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Diary;
|
||||
using Sarand.Net.Standard.Base.Interfaces;
|
||||
using Sarand.Net.Standard.Base.ItemData;
|
||||
using Sarand.Net.Standard.Base.ItemDocs;
|
||||
using Sarand.Net.Standard.Base.ItemOptions;
|
||||
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.Text;
|
||||
|
||||
namespace Sarand.BusinessMgr.Net.Core.Web.Models
|
||||
{
|
||||
//=======================================================================
|
||||
public class SbmModel_Base
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private SbmInternals internals;
|
||||
private readonly List<String> infoMessages = new List<string>();
|
||||
private readonly List<String> warningMessages = new List<string>();
|
||||
private readonly List<String> errorMessages = new List<string>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Protected construction.
|
||||
protected SbmModel_Base(SbmLocaliser localiser)
|
||||
{
|
||||
Localiser = localiser;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Application properties.
|
||||
private SbmApplication_Web App { get { return SbmApplication_Web.WebApp; } }
|
||||
protected SbmSessionConfig SessionConfig { get { return App.SessionConfig; } }
|
||||
protected SbmSystem_Web System { get { return App.System_Web; } }
|
||||
public String SessionCookieName { get { return App.SessionCookieName; } }
|
||||
public SbmSessionData SessionData { get { return SessionData_Web; } }
|
||||
public SbmSessionData_Web SessionData_Web { get; set; }
|
||||
public SbmSessionContext SessionContext { get { return SessionData?.SessionContext ?? App.SessionContext; } }
|
||||
public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SbmSystem.ComputerName); } }
|
||||
public bool DebugMode { get { return SbmSystem.DebugMode; } }
|
||||
public SbmLocaliser Localiser { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
public bool OK { get { return !HasMessages(); } }
|
||||
public virtual bool ProhibitCache { get; set; } = true;
|
||||
public String PageCaption { get; set; }
|
||||
public String InstanceVersion { get { return !StringUtil.IsEmpty(App.SessionConfig.Instance) ? App.SessionConfig.Instance + " v" + Sbm.Version.GetFullVersion() : "v" + Sbm.Version.GetAppVersion(); } }
|
||||
public bool IncludeGoogleAnalytics { get; set; } = false;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Business components.
|
||||
protected SbmInternals Internals { get { if (internals == null) internals = new SbmInternals(SessionData_Web.UserContext); return internals; } }
|
||||
// Managers.
|
||||
public SbmAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
|
||||
public SbmAssetMgr AssetMgr { get { return Internals.AssetMgr; } }
|
||||
public SbmCommodityMgr CommodityMgr { get { return Internals.CommodityMgr; } }
|
||||
public SbmPriceMgr PriceMgr { get { return Internals.PriceMgr; } }
|
||||
public SbmTransactionMgr TransactionMgr { get { return Internals.TransactionMgr; } }
|
||||
public SbmStockMgr StockMgr { get { return Internals.StockMgr; } }
|
||||
public SbmProcessMgr ProcessMgr { get { return Internals.ProcessMgr; } }
|
||||
public SbmDataItemMgr DataItemMgr { get { return Internals.DataItemMgr; } }
|
||||
// Consoles.
|
||||
public SbmConfigConsole ConfigConsole { get { return Internals.ConfigConsole; } }
|
||||
public SaDiaryConsole DiaryConsole { get { return Internals.DiaryConsole; } }
|
||||
public SaSecurityConsole SecurityConsole { get { return Internals.SecurityConsole; } }
|
||||
public SaCodeTypeConsole CodeTypeConsole { get { return Internals.CodeTypeConsole; } }
|
||||
public SaReferenceDataConsole ReferenceDataConsole { get { return Internals.ReferenceDataConsole; } }
|
||||
public SaUpdateLogConsole UpdateLogConsole { get { return Internals.UpdateLogConsole; } }
|
||||
public SaInterfaceConsole InterfaceConsole { get { return Internals.InterfaceConsole; } }
|
||||
public SaItemDocConsole ItemDocConsole { get { return Internals.ItemDocConsole; } }
|
||||
public SaItemOptionConsole ItemOptionConsole { get { return Internals.ItemOptionConsole; } }
|
||||
public SaItemDataConsole ItemDataConsole { get { return Internals.ItemDataConsole; } }
|
||||
// Configurations.
|
||||
public SbmStockControlConfig StockControlConfig { get { return Internals.StockControlConfig; } }
|
||||
public SbmRequirementCostingConfig RequirementCostingConfig { get { return Internals.RequirementCostingConfig; } }
|
||||
// System codes.
|
||||
public List<TypeCodeDesc> GetCodesOfType(Sbm.SystemCode systemCode) { return Internals.GetCodesOfType(systemCode); }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Security.
|
||||
public bool ValidUserSession { get { return SessionData?.ValidUserSession ?? false; } }
|
||||
public bool AwaitingLogin { get { return !ValidUserSession; } }
|
||||
public bool KeepLoggedIn { get { return !AwaitingLogin && SessionData.User.KeepLoggedIn; } }
|
||||
/// <summary>Maximum length allowed for password entry: sign-up, change password etc.</summary>
|
||||
public int PasswordMaxLength { get; } = 32;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Form control value max length.
|
||||
/// <para>In many cases the database columns allow plenty of extra space for the value, in case they need to be encrypted.</para>
|
||||
/// <para>Hence, several cases where the value entered in the control isn't allowed the full database length.</para>
|
||||
/// </summary>
|
||||
public int GetControlMaxLength(SbmDbDfn.ColumnIdx column)
|
||||
{
|
||||
int maxLength = (int)SbmDbDfn.GetColTextLen(column);
|
||||
switch (column)
|
||||
{
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_Email:
|
||||
return Math.Min(maxLength, 60);
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_FirstName:
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_LastName:
|
||||
return Math.Min(maxLength, 40);
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_Name:
|
||||
return Math.Min(maxLength, 80);
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_PhoneMain:
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_PhoneMobile:
|
||||
case SbmDbDfn.ColumnIdx.Affiliate_PhoneAlt:
|
||||
return Math.Min(maxLength, 20);
|
||||
case SbmDbDfn.ColumnIdx.Address_Postcode:
|
||||
return Math.Min(maxLength, 16);
|
||||
}
|
||||
return maxLength;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Copyright notice.
|
||||
public HtmlString CopyrightNotice
|
||||
{
|
||||
get
|
||||
{
|
||||
int initialYear = 2020;
|
||||
int currentYear = DateTime.Today.Year;
|
||||
return Localiser.GetHtmlText("copyright.symbol.year.html", (initialYear != currentYear ? initialYear + "-" : "") + currentYear.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form data - Dates.
|
||||
// Format may depend on locale, but as long as these methods are used consistently,
|
||||
// there should be consistent formatting, display and parsing of date values.
|
||||
public String CalendarDateFormat
|
||||
{
|
||||
get
|
||||
{
|
||||
// JQuery-UI DatePicker date format.
|
||||
// Format:
|
||||
// d Single digit day of month
|
||||
// dd Double digit day of month
|
||||
// D 3 letter day of week abbreviation.
|
||||
// DD Day of week.
|
||||
// m Single digit month.
|
||||
// mm Double digit month.
|
||||
// M 3 letter month abbreviation.
|
||||
// MM Month name.
|
||||
// yy 4 digit year.
|
||||
// Examples:
|
||||
// dd/mm/yy 07/04/2012
|
||||
// dd-M-yy 07-Apr-2012
|
||||
// d-M-yy 7-Apr-2012
|
||||
return "dd-M-yy";
|
||||
}
|
||||
}
|
||||
public String FormatDateForForm(DateTime value)
|
||||
{
|
||||
return DateUtil.Format(value, "dd-MMM-yyyy");
|
||||
}
|
||||
public DateTime ParseDateFromForm(String value)
|
||||
{
|
||||
return DateUtil.ParseExact(value, "dd-MMM-yyyy");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Link URLs.
|
||||
public class LinksData
|
||||
{
|
||||
public String Facebook { get; } = "https://www.facebook.com/BusinessMgr/";
|
||||
public String LinkedIn { get; } = "https://www.linkedin.com/company/BusinessMgr/about/";
|
||||
}
|
||||
public LinksData Links { get; } = new LinksData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form data.
|
||||
|
||||
/// <summary>List of Address Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> AddressTypeCodesForSelect
|
||||
{
|
||||
get { return new SelectList(GetCodesOfType(Sbm.SystemCode.AddressType), "Code", "Desc"); }
|
||||
}
|
||||
|
||||
/// <summary>List of Affiliate Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> AffiliateTypeCodesForSelect
|
||||
{
|
||||
get { return new SelectList(GetCodesOfType(Sbm.SystemCode.AffiliateType), "Code", "Desc"); }
|
||||
}
|
||||
|
||||
/// <summary>List of Association Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> AssociationTypeCodesForSelect
|
||||
{
|
||||
get { return new SelectList(GetCodesOfType(Sbm.SystemCode.AssociationType), "Code", "Desc"); }
|
||||
}
|
||||
|
||||
/// <summary>List of Commodity Types for dropdown.</summary>
|
||||
public IEnumerable<SelectListItem> CommodityTypeCodesForSelect
|
||||
{
|
||||
get { return new SelectList(GetCodesOfType(Sbm.SystemCode.CommodityType), "Code", "Desc"); }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Version parameter for includes.
|
||||
public String HrefVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
DateTime versionDate = SbmSystem.AssemblyBuildAt;
|
||||
if (!DateUtil.IsValid(versionDate) || SbmSystem.DebugMode)
|
||||
versionDate = DateTime.Now;
|
||||
return DateUtil.Format(versionDate, "yyyyMMdd" /*+ (SacsSystem.Debug ? "HHmm" : "")*/);
|
||||
}
|
||||
}
|
||||
// Additional includes.
|
||||
public List<String> AdditionalFiles_CSS { get; set; } = new List<string>();
|
||||
public List<String> AdditionalFiles_JS { get; set; } = new List<string>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
public class RedirectLocationData
|
||||
{
|
||||
// Properties populated in Controller_Base.OnActionExecuted.
|
||||
public String Base { get; internal set; }
|
||||
public String Home { get; internal set; }
|
||||
public String Home_SessionExpired { get; internal set; }
|
||||
}
|
||||
public RedirectLocationData RedirectLocation { get; } = new RedirectLocationData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Paging properties.
|
||||
public class DataPaging
|
||||
{
|
||||
private DbQuery.Paging paging { get; } = new DbQuery.Paging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
resultsPaging.PageLength = paging.PageLength;
|
||||
resultsPaging.PageNo = paging.PageNo;
|
||||
}
|
||||
public bool IsPaged { get { return paging.Paged; } }
|
||||
public uint PageNo { get { return paging.PageNo; } set { paging.PageNo = value; } }
|
||||
public ushort PageLength { get { return paging.PageLength; } set { paging.PageLength = value; } }
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / PageLength) : 0); } }
|
||||
public ushort ItemCount { get; set; }
|
||||
private ulong itemTotal = 0;
|
||||
public ulong ItemTotal
|
||||
{
|
||||
get { return itemTotal; }
|
||||
set
|
||||
{
|
||||
itemTotal = value;
|
||||
// Check whether the total number of items is less than the current page and reduce page no if needed.
|
||||
if (IsPaged && (PageNo - 1) * PageLength > itemTotal)
|
||||
PageNo = (uint)((itemTotal - 1) / PageLength + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public DataPaging Paging { get; } = new DataPaging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
Paging.PopulatePagingTo(resultsPaging);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form properties.
|
||||
/// <summary>
|
||||
/// User session index to identify the site resources, eg. database.
|
||||
/// <para>Equivalent to the Site index on the login form.</para>
|
||||
/// <para>Populates value on logout form to identify default site for next login.</para>
|
||||
/// </summary>
|
||||
public ushort SessionIdx { get { return SessionContext.Index; } }
|
||||
public String FormAction { get; set; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Messages.
|
||||
//-------------------------------------------------------------------
|
||||
public bool HasMessages()
|
||||
{
|
||||
return infoMessages.Count > 0 || warningMessages.Count > 0 || errorMessages.Count > 0;
|
||||
}
|
||||
public List<String> InfoMessages { get { return new List<string>(infoMessages); } }
|
||||
public List<String> WarningMessages { get { return new List<string>(warningMessages); } }
|
||||
public List<String> ErrorMessages { get { return new List<string>(errorMessages); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form messages.
|
||||
public void AddInfoMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
infoMessages.Add(message);
|
||||
}
|
||||
public void AddWarningMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
warningMessages.Add(message);
|
||||
}
|
||||
public void AddErrorMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
errorMessages.Add(message);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
Reference in New Issue
Block a user