This commit is contained in:
2022-02-16 10:47:45 +00:00
parent 5d15b28456
commit 4a394d3ff7
75 changed files with 3127 additions and 691 deletions
@@ -37,6 +37,20 @@ namespace Saxonite.Net.Core.Web.Online.Consoles
return dataCacheConsole;
}
//-------------------------------------------------------------------
// Session Data console.
private readonly Dictionary<ushort, SaxSessionDataConsole_Online> sessionDataConsoles = new Dictionary<ushort, SaxSessionDataConsole_Online>();
public override SaxSessionDataConsole GetSessionDataConsole(SaxSessionContext sessionContext)
{
if (sessionContext == null) throw new NotSupportedException(GetType().Name + ".GetSessionDataConsole Session Context must be specified");
SaxSessionDataConsole_Online sessionDataConsole = sessionDataConsoles.GetValueOrDefault(sessionContext.Index, null);
if (sessionDataConsole == null)
{
sessionDataConsole = sessionDataConsoles[sessionContext.Index] = new SaxSessionDataConsole_Online(sessionContext);
}
return sessionDataConsole;
}
//-------------------------------------------------------------------
// Activity console.
public override SaxActivityConsole CreateActivityConsole(SaxSessionContext sessionContext)
@@ -15,6 +15,7 @@ namespace Saxonite.Net.Core.Web.Online.Consoles
private System.Timers.Timer refreshTimer;
//-------------------------------------------------------------------
// Construction.
public SaxDataCacheConsole_Online(SaxSessionContext sessionContext) :
base(sessionContext)
{
@@ -0,0 +1,119 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Net.Core.Web.Base.Consoles;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using Saxonite.Net.Standard.Base.Consoles;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Saxonite.Net.Core.Web.Online.Consoles
{
//=======================================================================
public class SaxSessionDataConsole_Online : SaxSessionDataConsole_Web
{
//-------------------------------------------------------------------
// Definitions.
//-------------------------------------------------------------------
// Data members.
private static SaxSessionDataConsole_Online console = null;
private System.Timers.Timer commitTimer = null;
/// <summary>Latest time that a user was active on the online system - awaiting commit to the database.</summary>
private SacsQueueDictionary<SysId, SaxUserOnline.DataProperties> usersActiveAt = new SacsQueueDictionary<SysId, SaxUserOnline.DataProperties>();
private DateTime lastDataCommit = DateTime.MinValue;
private int commitBatchSize = 32;
//-------------------------------------------------------------------
// Construction.
public SaxSessionDataConsole_Online(SaxSessionContext sessionContext) :
base(sessionContext)
{
String fn = GetType().Name + ".CTR";
if (console != null)
{
SaLogger.Info(fn + " Instance already exists");
throw new InvalidOperationException(GetType().Name + " - instance already exists.");
}
console = this;
SaLogger.Info(fn + "");
// Initilise commit timer.
commitTimer = new System.Timers.Timer(Math.Max(2, Sax.Config.Online.DataCache.RefreshIntervalSecs.Initial) * 1000);
commitTimer.Elapsed += CommitTimer_Elapsed;
commitTimer.Start();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (Object.ReferenceEquals(console, this))
console = null;
}
base.Dispose(disposing);
}
//-------------------------------------------------------------------
// Properties.
//-------------------------------------------------------------------
// Utilities.
//-------------------------------------------------------------------
// Record User Online activity.
//-------------------------------------------------------------------
public override bool RecordUserActive(SysId userAccountId, DateTime activeAt)
{
if (!SysId.IsValid(userAccountId) || !DateUtil.IsValid(activeAt)) return false;
usersActiveAt.SetEntry(userAccountId, new SaxUserOnline.DataProperties() { UserAccountId = userAccountId, OnlineAt = activeAt });
return true;
}
//-------------------------------------------------------------------
// Commit User Online activity.
//-------------------------------------------------------------------
public override DateTime LastDataCommit()
{
lock (usersActiveAt)
return lastDataCommit;
}
private void CommitTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
commitTimer.Stop();
CommitData();
}
private void CommitData()
{
String fn = GetType().Name + ".CommitData";
commitTimer.Stop();
// Extract data to be committed.
List<KeyValuePair<SysId, SaxUserOnline.DataProperties>> usersActiveAtToCommit = usersActiveAt.RemoveTopEntries(commitBatchSize);
// Reset the timer.
int intervalSecs = Sax.Config.Online.Session.DataCommit.IntervalSecs.NoDataWaiting;
if (usersActiveAt.Count > 0)
{
// Additional Data is waiting to be committed.
intervalSecs = Sax.Config.Online.Session.DataCommit.IntervalSecs.DataWaiting;
}
commitTimer.Interval = Math.Max(1, intervalSecs) * 1000;
commitTimer.Start();
// Commit the data.
if (usersActiveAtToCommit.Count > 0)
{
if (SacsSystem.DebugMode)
SaLogger.Info(fn + " Entries to commit: " + usersActiveAtToCommit.Count);
Internals.AccountMgr.CommitUsersOnline(usersActiveAtToCommit.Select(ItemId => ItemId.Value).ToList());
}
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -48,9 +48,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
[HttpPost]
[Route("Search/Ajax/Organisations")]
[Route("Search/Ajax/GetOrganisations")]
public IActionResult GetProfileOrganisations(Model_Search_Organisations model)
public IActionResult Ajax_GetOrganisations(Model_Search_Organisations model)
{
String fn = GetType().Name + ".GetProfileOrganisations";
String fn = GetType().Name + ".Ajax_GetOrganisations";
AjaxResponse_Search_Organisations responseData = new AjaxResponse_Search_Organisations(model);
String messageTitle = Localiser["organisation.caption.organisations"];
@@ -68,6 +68,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
prmOrganisation.OrganisationFilter = model.Filter.Organisation;
prmOrganisation.OrganisationType = model.FilterOrganisationType;
prmOrganisation.OrganisationCategory = model.FilterOrganisationCategory;
prmOrganisation.OrganisationCategoriesExcluded.Add(Sax.OrganisationCategory.Partner);
prmOrganisation.OrganisationCategoriesExcluded.Add(Sax.OrganisationCategory.Other);
if (SysId.IsValid(model.FilterSportId))
prmOrganisation.SportIdsIncluded.Add(model.FilterSportId);
if (SysId.IsValid(model.FilterRegionId))
@@ -151,9 +153,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
[HttpPost]
[Route("Search/Ajax/Organisation")]
[Route("Search/Ajax/GetOrganisation")]
public IActionResult GetProfileOrganisation(Model_Search_Organisations model)
public IActionResult Ajax_GetOrganisation(Model_Search_Organisations model)
{
String fn = GetType().Name + ".GetProfileOrganisation";
String fn = GetType().Name + ".Ajax_GetOrganisation";
AjaxResponse_Search_Organisation responseData = new AjaxResponse_Search_Organisation(model);
String messageTitle = Localiser["label.organisation"];
@@ -43,9 +43,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
[HttpPost]
[Route("Search/Ajax/Users")]
[Route("Search/Ajax/GetUsers")]
public IActionResult GetProfileUsers(Model_Search_Users model)
public IActionResult Ajax_GetUsers(Model_Search_Users model)
{
String fn = GetType().Name + ".GetProfileUsers";
String fn = GetType().Name + ".Ajax_GetUsers";
AjaxResponse_Search_Users responseData = new AjaxResponse_Search_Users(model);
String messageTitle = Localiser["label.users"];
@@ -54,18 +54,19 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
RefreshModel(model);
// Ensure data is paged to avoid leaking large volumes.
model.Paging.PageNo = Math.Max(1, model.Paging.PageNo);
model.Paging.PageLength = Math.Max(Math.Min(Sax.Config.Online.Search.Users.PageLengthMax, model.Paging.PageLength), (ushort)1);
// Ensure filter has something to restrict the list.
// ToDo May be able to show some results, such as friends when no filter provided.
if (StringUtil.IsEmpty(StringUtil.TrimAll(model.Filter.User)))
{
responseData.SetPaging(model);
responseData.Success = true;
return Json(responseData);
}
// Ensure data is paged to avoid leaking large volumes.
model.Paging.PageNo = Math.Max(1, model.Paging.PageNo);
model.Paging.PageLength = Math.Max(Math.Min(Sax.Config.Online.Search.Users.PageLengthMax, model.Paging.PageLength), (ushort)1);
// Query users that user is a member of.
SaxUserAccount.Params prmUserAccount = new SaxUserAccount.Params();
prmUserAccount.UserFilter = model.Filter.User;
@@ -142,9 +143,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
[HttpPost]
[Route("Search/Ajax/User")]
[Route("Search/Ajax/GetUser")]
public IActionResult GetProfileUser(Model_Search_Users model)
public IActionResult Ajax_GetUser(Model_Search_Users model)
{
String fn = GetType().Name + ".GetProfileUser";
String fn = GetType().Name + ".Ajax_GetUser";
AjaxResponse_Search_User responseData = new AjaxResponse_Search_User(model);
String messageTitle = Localiser["label.user"];
@@ -77,6 +77,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
public ActionResult Ajax_KeepLoggedIn(Model_Security model)
{
String fn = GetType().Name + ".Ajax_KeepLoggedIn";
if (DebugMode) SaLogger.Debug(fn);
AjaxResponse_KeepLoggedIn responseData = new AjaxResponse_KeepLoggedIn();
// Validate session and referrer.
@@ -6,6 +6,7 @@ using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
@@ -130,7 +131,7 @@ namespace Saxonite.Net.Core.Web.Online.Models
responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]);
else if (!DateUtil.IsValid(publishedOn))
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
else if (publishedOn.CompareTo(DateTime.Today) > 0)
else if (publishedOn.CompareTo(DateUtil.IncrementDate(DateTime.Today, Sax.Config.Online.Articles.PublishMaxDaysAhead)) > 0)
responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]);
}
@@ -11,6 +11,7 @@
<ItemGroup>
<PackageReference Include="jQuery.UI.Combined" Version="1.12.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.16" />
<PackageReference Include="System.Collections.Specialized" Version="4.3.0" />
</ItemGroup>
<ItemGroup>
@@ -7,6 +7,7 @@
<div class="sax-panel Articles">
<script type="text/javascript">
sax.maxPublishDaysAhead = '@(Sax.Config.Online.Articles.PublishMaxDaysAhead)';
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
</script>
@@ -122,7 +122,7 @@
<div class="col">@Html.TextBoxFor(model => model.ArticlePublishOn, new { @id = "ifArticlePublishOn", @class = "sax-input sax-calendar ArticlePublishOn", @readonly = "readonly" })</div>
</div>
<div class="row ArticlePublished">
<div class="col"><div class="pl16">@Localiser["label.published"]: <span class="ArticlePublishedOn"></span></div></div>
<div class="col"><div class="">@Localiser["label.published"]: <span class="ArticlePublishedOn"></span></div></div>
</div>
</div>
<div class="sax-message"></div>
@@ -35,7 +35,7 @@
<label for=""><span>@Localiser["label.category"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control">
@Html.DropDownList("", Model.OrganisationCategoriesForSelect, Localiser["label.select"], new { @id = "", @name = "Organisation.Category", @class = "OrganisationCategory sax-select" })
@Html.DropDownList("", Model.OrganisationCategoriesForSelect, Localiser["label.select"] + ":", new { @id = "", @name = "Organisation.Category", @class = "OrganisationCategory sax-select" })
</div>
<div class="sax-message"></div>
</div>
@@ -48,7 +48,7 @@
<label for=""><span>@Localiser["label.type"]</span><span class="required">&nbsp;*</span></label>
</div>
<div class="sax-control">
@Html.DropDownList("", Model.OrganisationTypesForSelect, Localiser["label.select"], new { @id = "", @name = "Organisation.Type", @class = "OrganisationType sax-select" })
@Html.DropDownList("", Model.OrganisationTypesForSelect, Localiser["label.select"] + ":", new { @id = "", @name = "Organisation.Type", @class = "OrganisationType sax-select" })
</div>
<div class="sax-message"></div>
</div>
@@ -9,8 +9,8 @@
@* Results paging *@
<div class="sax-results-paging hidden">
@Html.HiddenFor(model => model.Paging.PageNo, new { @id = "", @class = "PagingPageNo" })
@Html.HiddenFor(model => model.Paging.PageLength, new { @id = "", @class = "PagingPageLength" })
@Html.HiddenFor(model => model.Paging.PageNoValue, new { @id = "", @class = "PagingPageNo" })
@Html.HiddenFor(model => model.Paging.PageLengthValue, new { @id = "", @class = "PagingPageLength" })
<div class="iblock sax-action sax-paging-first"><img src="~/img/action/first24.png" alt="@(Localiser["label.first"])" title="@(Localiser["label.first"])" /></div>
<div class="iblock sax-action sax-paging-prev"><img src="~/img/action/prev24.png" alt="@(Localiser["label.previous"])" title="@(Localiser["label.previous"])" /></div>
@@ -53,7 +53,7 @@
@* Organisation type *@
<div class="sax-control row">
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.type"]</div></div>
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.category"]</div></div>
<div class="col-sm">
@Html.DropDownListFor(model => model.Filter.Category, Model.OrganisationCategoriesForSelect, Localiser["label.any"], new { @id = "", @class = "FilterCategory sax-select" })
</div>
@@ -15,6 +15,11 @@
<div class="spacer"></div>
<div class="row UserName">
<div class="col-sm-5"><div class="sax-label text-sm-right">@Localiser["label.name"]</div></div>
<div class="col-sm"><div class="sax-value"></div></div>
</div>
<div class="row UserLocation">
<div class="col-sm-5"><div class="sax-label text-sm-right">@Localiser["label.location"]</div></div>
<div class="col-sm"><div class="sax-value"></div></div>
@@ -54,9 +54,8 @@
}
@* Scripts *@
<script>
var sax = sax || {
page: {}, url: {}, links: {}, data: {}, form: {}, mdl: {}, ajax: {}, msg: {}, lbl: {}, dlg: { title: {}, btn: {} }, $frm: {}, $dlg: {}, $pnl: {} };
<script>
var sax = sax || { page: {}, url: {}, links: {}, data: {}, form: {}, mdl: {}, ajax: {}, msg: {}, lbl: {}, dlg: { title: {}, btn: {} }, $frm: {}, $dlg: {}, $pnl: {}, session: {}, kli: {} };
sax.url.base = '@Model.RedirectLocation.Base';
sax.url.home = '@Model.RedirectLocation.Home';
sax.url.sessionExpired = '@Model.RedirectLocation.Home_SessionExpired';
@@ -87,12 +86,12 @@
sax.msg.dataQuerying = '@Localiser.GetJavascriptText("msg.data.querying")';
sax.msg.dataNoneFound = '@Localiser.GetJavascriptText("msg.data.noneFound")';
sax.maxProfileImageSize = 2*10**6;
sax.sessionCookieName = '@Model.SessionCookieName';
sax.session.cookieName = '@Model.SessionCookieName';
sax.awaitingLogin = @awaitingLogin;
sax.keepLoggedIn = @keepLoggedIn;
sax.keepLoggedInDelay = @(Sax.Config.Admin.Session.Cookie.KeepLoggedInTimeoutMillis);
sax.kli.active = @keepLoggedIn;
sax.kli.interval = @(Sax.Config.Admin.Session.Cookie.KeepLoggedInTimeoutMillis);
sax.debugMode = @debug;
</script>
</script>
</head>
<body>
+4 -2
View File
@@ -142,6 +142,8 @@
$('#ifArticleOrganisation', $frmA).val($('#ifFilterOrganisation', $frmF).val());
$('.sax-form-control.ArticleOrganisation', $frmA).toggle(!!orgId);
$('#chkArticlePublish', $frmA).prop("checked", false);
$('div.ArticlePublish', $frmA).show();
$('div.ArticlePublished', $frmA).hide();
$('.sax-input.sax-calendar.ArticlePublishOn', $frmA).datepicker('setDate', 'today');
sax.clearControlErrors();
}
@@ -462,7 +464,7 @@
});
$frm.articleId = $('#frmArticleId');
$frm.article = $('#frmArticle');
$('.sax-input', $frm.article).on('input', function () { sax.clearControlError(this); });
$('.sax-input,.sax-textarea', $frm.article).on('input', function () { sax.clearControlError(this); });
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.cancel] = { text: sax.dlg.btn.cancel, class: "floatr", click: function () { $(this).dialog('close'); } };
@@ -473,7 +475,7 @@
ac.$content = $('.sax-article-panel.sax-article-content');
ac.$segList = $('.sax-article-segment-list', ac.$content);
sax.initCalendars('.sax-input.sax-calendar').datepicker('option', { maxDate: '+00' });
sax.initCalendars('.sax-input.sax-calendar').datepicker('option', { maxDate: '+' + (sax.maxPublishDaysAhead||'0') });
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.uploadArticleImage(); };
+15 -24
View File
@@ -21,6 +21,10 @@
{
return !isNaN(parseFloat(n)) && isFinite(n);
}
sax.getTime = function ()
{
return (new Date()).getTime();
}
sax.zeroPad = function (num, count)
{
var val = num + '';
@@ -123,7 +127,7 @@
{
return $(sel).datepicker(opt || {});
}
sax.allowClearCalendar = function(sel)
sax.allowClearCalendar = function (sel)
{
$(sel).datepicker().on('keyup', function (e)
{
@@ -375,39 +379,26 @@
//--------------------------------------------------------------
// Session.
sax.configureKeepLoggedIn = function ()
sax.configureKeepLoggedIn = function (single)
{
//sax.debug('KeepLoggedIn Configuring');
setTimeout(sax.doKeepLoggedIn, Math.max(30000, sax.keepLoggedInDelay || 300000));
let kli = sax.kli;
if (!kli.timeout) kli.timeout = setTimeout(function () { sax.doKeepLoggedIn(single); }, Math.max(30000, kli.interval || 300000));
}
sax.doKeepLoggedIn = function ()
sax.doKeepLoggedIn = function (single)
{
//sax.debug('KeepLoggedIn Calling');
var onKeepLoggedIn = function (response)
{
//sax.debug('KeepLoggedIn Responded', response);
sax.configureKeepLoggedIn();
}
sax.doAjaxRequest({ url: sax.url.base + 'Security/Ajax/KeepLoggedIn', formId: 'frmNavigate', noWaitIcon: true, callbackFn: onKeepLoggedIn }, 1000)
let kli = sax.kli;
delete kli.timeout;
sax.doAjaxRequest({ url: sax.url.base + 'Security/Ajax/KeepLoggedIn', formId: 'frmNavigate', noWaitIcon: true, callbackFn: function (response) { kli.lastAt = sax.getTime(); if (!single) sax.configureKeepLoggedIn(); } }, 1000)
}
sax.configureSessionRefresh = function ()
{
//sax.debug('SessionRefresh Configuring');
$(document).on('mousedown mousemove touchstart scroll keydown', sax.triggeRefreshSession);
}
sax.triggeRefreshSession = function ()
{
sax.session = sax.session || { refresh: {} };
let ssr = sax.session.refresh;
win.clearTimeout(ssr.timeout);
ssr.timeout = setTimeout(function () { sax.refreshSession(); }, 150000);
if (sax.kli.timeout) return;
sax.configureKeepLoggedIn(1);
}
sax.refreshSession = function ()
{
//sax.debug('sax.refreshSession');
sax.doKeepLoggedIn();
}
//--------------------------------------------------------------
// Data entry.
sax.clearControlErrors = function (context)
@@ -520,7 +511,7 @@
$(function ()
{
$('.sax-button-cta,.sax-button-action,.sax-action-link,.sax-social-icon.sax-action').prop('tabindex', 0);
if (sax.keepLoggedIn)
if (sax.kli.active)
sax.configureKeepLoggedIn();
else if (!sax.awaitingLogin)
sax.configureSessionRefresh();
@@ -135,7 +135,7 @@
if (!response.success) return;
let dlg = $dlg.usr;
let item = su.data.user = response.user;
$('.UserName', dlg).val(item.name);
$('.UserName', dlg).find('.sax-value').text(item.name);
$('.UserLocation', dlg).toggle(!!item.location).find('.sax-value').text(item.location);
sax.clearControlErrors();
$dlg.usr.dialog('option', 'title', item.name || sax.dlg.title.user);