294 lines
13 KiB
C#
294 lines
13 KiB
C#
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 Sacs.Web.Components;
|
|
using Sarand.Net.Standard.Base.App;
|
|
using Sarand.Net.Standard.Base.Bus;
|
|
using Sarand.Net.Standard.Base.Core;
|
|
using Sarand.Net.Standard.Base.Dbas;
|
|
using Sarand.Net.Standard.Base.Email;
|
|
using Sarand.Net.Standard.Base.Helpers;
|
|
using Sarand.Net.Standard.Base.Utils;
|
|
using Saxonite.Net.Core.Web.Base.App;
|
|
using Saxonite.Net.Core.Web.Base.Consoles;
|
|
using Saxonite.Net.Core.Web.Base.Models;
|
|
using Saxonite.Net.Standard.Base.App;
|
|
using Saxonite.Net.Standard.Base.Bus;
|
|
using Saxonite.Net.Standard.Base.Consoles;
|
|
using Saxonite.Net.Standard.Base.Mgr;
|
|
using Saxonite.Net.Standard.Base.Mgr.Support;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Specialized;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Web;
|
|
|
|
namespace Saxonite.Net.Core.Web.Base.Controllers
|
|
{
|
|
//=======================================================================
|
|
public abstract class SaxController_Base : SaController
|
|
{
|
|
//-------------------------------------------------------------------
|
|
// Data members.
|
|
private SaxInternals internals;
|
|
|
|
//-------------------------------------------------------------------
|
|
// Protected construction.
|
|
protected SaxController_Base(SaxLocaliser localiser)
|
|
{
|
|
Localiser = localiser;
|
|
|
|
// Initialise console (debug) logging listener.
|
|
//if (Directory.Exists(App.LoggingRootFolder) && SaxSystem.DebugMode)
|
|
// SaxConsoleListener.ConfigureDebugListener(App.LoggingRootFolder);
|
|
if (DebugMode) SaLogger.Trace(GetType().Name + ".CTR");
|
|
}
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
}
|
|
base.Dispose(disposing);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Properties.
|
|
protected SaxApplication_Web App { get { return SaxApplication_Web.WebApp; } }
|
|
public SaxAppConfig AppConfig { get { return App.AppConfig; } }
|
|
public SaxSessionContext SessionContext { get { return App.SessionContext; } }
|
|
public SaxLocaliser Localiser { get; }
|
|
|
|
//-------------------------------------------------------------------
|
|
// Globals.
|
|
protected SaxConsoleHelper ConsoleHelper { get { return SaxGlobals.ConsoleHelper; } }
|
|
|
|
//-------------------------------------------------------------------
|
|
// Business components.
|
|
public SaxInternals Internals { get { if (internals == null) internals = new SaxInternals(SessionContext); return internals; } }
|
|
// Consoles.
|
|
public SaxDataCacheConsole DataCacheConsole { get { return Internals.DataCacheConsole; } }
|
|
public SaxSessionDataConsole SessionDataConsole { get { return Internals.SessionDataConsole; } }
|
|
public SaxActivityConsole ActivityConsole { get { return Internals.ActivityConsole; } }
|
|
// Managers.
|
|
public SaxReferenceMgr ReferenceMgr { get { return Internals.ReferenceMgr; } }
|
|
public SaxAccountMgr AccountMgr { get { return Internals.AccountMgr; } }
|
|
public SaxActivityMgr ActivityMgr { get { return Internals.ActivityMgr; } }
|
|
public SaxItemDataMgr ItemDataMgr { get { return Internals.ItemDataMgr; } }
|
|
public SaxSupportMgr SupportMgr { get { return Internals.SupportMgr; } }
|
|
// System codes.
|
|
public List<TypeCodeDesc> DataItemTypeCodes { get { return Internals.DataItemTypeCodes; } }
|
|
public List<TypeCodeDesc> SportSpecialityLabelCodes { get { return Internals.SportSpecialityLabelCodes; } }
|
|
public List<TypeCodeDesc> SportContactTypeCodes { get { return Internals.SportContactTypeCodes; } }
|
|
public List<TypeCodeDesc> SportParticipatingCodes { get { return Internals.SportParticipatingCodes; } }
|
|
public List<TypeCodeDesc> SportPreparingCodes { get { return Internals.SportPreparingCodes; } }
|
|
public List<TypeCodeDesc> SportOfficiatingCodes { get { return Internals.SportOfficiatingCodes; } }
|
|
public List<TypeCodeDesc> RegionTypeCodes { get { return Internals.RegionTypeCodes; } }
|
|
public List<TypeCodeDesc> EligibilityTypeCodes { get { return Internals.EligibilityTypeCodes; } }
|
|
public List<TypeCodeDesc> UserRoleCodes { get { return Internals.UserRoleCodes; } }
|
|
public List<TypeCodeDesc> OrganisationTypeCodes { get { return Internals.OrganisationTypeCodes; } }
|
|
public List<TypeCodeDesc> OrganisationCategoryCodes { get { return Internals.OrganisationCategoryCodes; } }
|
|
public List<TypeCodeDesc> OrganisationRoleCodes { get { return Internals.OrganisationRoleCodes; } }
|
|
public List<TypeCodeDesc> AssociationTypeCodes { get { return Internals.AssociationTypeCodes; } }
|
|
public List<TypeCodeDesc> AddressTypeCodes { get { return Internals.AddressTypeCodes; } }
|
|
public List<TypeCodeDesc> ContactMethodCodes { get { return Internals.ContactMethodCodes; } }
|
|
public List<TypeCodeDesc> EventTypeCodes { get { return Internals.EventTypeCodes; } }
|
|
public List<TypeCodeDesc> OpportunityTypeCodes { get { return Internals.OpportunityTypeCodes; } }
|
|
public List<TypeCodeDesc> ActivityReactionCodes { get { return Internals.ActivityReactionCodes; } }
|
|
// Support.
|
|
public List<TypeCodeDesc> UserReportTypeCodes { get { return Internals.UserReportTypeCodes; } }
|
|
// Email.
|
|
public SaEmailConfig EmailConfig { get { return App.EmailConfig; } }
|
|
public SaxEmailConsole EmailConsole { get { return Internals.EmailConsole; } }
|
|
|
|
//-------------------------------------------------------------------
|
|
// 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.
|
|
SaxModel_Base baseModel = ViewData.Model as SaxModel_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.
|
|
SaxModel_Base baseModel = ViewData.Model as SaxModel_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_SessionData, SessionStorage.sessionDataEncoding.GetBytes(sessionDataJson));
|
|
}
|
|
}
|
|
else HttpContext.Session.Remove(SessionStorage.SessionKey_SessionData);
|
|
|
|
// 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(SaxModel_Base model)
|
|
{
|
|
if (model == null) return;
|
|
|
|
// Session data.
|
|
model.Controller = this;
|
|
model.SessionData = SessionData;
|
|
|
|
// Redirect locations.
|
|
model.RedirectLocation.Base = GetRedirectLocation(RedirectLocation.WebAppBase);
|
|
model.RedirectLocation.Home = GetRedirectLocation(RedirectLocation.WebAppHome);
|
|
model.RedirectLocation.Home_SessionExpired = GetRedirectLocation(RedirectLocation.WebAppHome_SessionExpired);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Parameters.
|
|
//-------------------------------------------------------------------
|
|
// Online Request Password encryption parameters (key & IV) are defined in
|
|
// the base Controller so that they can be shared with the Adnin application.
|
|
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
|
|
// IV Must be regenerated if key is changed.
|
|
protected static String Base64Key_RequestPassword_Online { get; } = SacsEncryptionHelper.EncodePlainKey("{~Saxonite@@Request^Password=}", SacsEncryptionHelper.KeyLength);
|
|
//private static String Base64IV_RequestPassword_Generated_Online { get; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_RequestPassword_Online);
|
|
protected static String Base64IV_RequestPassword_Online { get; } = "1VAWYTW6d72n/6HDNhbqow==";
|
|
|
|
//-------------------------------------------------------------------
|
|
// Session.
|
|
//-------------------------------------------------------------------
|
|
private bool UserActiveRecorded { get; set; } = false;
|
|
public bool ValidUserSession
|
|
{
|
|
get
|
|
{
|
|
if (SessionData == null || !SessionData.ValidUserSession) return false;
|
|
SaxSessionDataConsole sessionDataConsole = SessionDataConsole;
|
|
if (sessionDataConsole != null && !UserActiveRecorded)
|
|
{
|
|
// Record the user as active once per request.
|
|
sessionDataConsole.RecordUserActive(SessionUserAccountId, CreatedAt);
|
|
UserActiveRecorded = true;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
public SysId SessionUserAccountId { get { return SessionData?.User?.UserAccountId ?? null; } }
|
|
public DbUpdateInfo DbUpdateInfo { get { return SessionData?.DbUpdateInfo ?? new DbUpdateInfo(null, "", SaxSystem.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(SaxSessionData 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 SaxSessionData SessionData { get; set; }
|
|
public static String SessionKey_SessionData { get; } = "SaxSessionData";
|
|
public static Encoding sessionDataEncoding { get; } = Encoding.UTF8;
|
|
//JSON Serialisation.
|
|
public class SaxSessionDataContractResolver : 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 SaxSessionDataContractResolver(),
|
|
// Force all deserialised objects to be replaced - to avoid proxy lists not populating.
|
|
ObjectCreationHandling = ObjectCreationHandling.Replace
|
|
};
|
|
}
|
|
private readonly SessionStorage sessionStorage = new SessionStorage();
|
|
protected JsonSerializerSettings SaxSessionDataJsonSerializerSettings { get { return SessionStorage.JsonDeserialisationSettings; } }
|
|
|
|
//-------------------------------------------------------------------
|
|
public SaxSessionData SessionData
|
|
{
|
|
get
|
|
{
|
|
try
|
|
{
|
|
// Retrieve session data if not already in controller.
|
|
if (sessionStorage.SessionData == null)
|
|
{
|
|
byte[] sessionDataBytes = null;
|
|
HttpContext.Session.TryGetValue(SessionStorage.SessionKey_SessionData, 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 SaxSessionData DeserializeSessionData(String sessionDataJson);
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|