340 lines
14 KiB
C#
340 lines
14 KiB
C#
using Sarand.Net.Standard.Base.Bus;
|
|
using Sarand.Net.Standard.Base.Core;
|
|
using Sarand.Net.Standard.Base.Dbas;
|
|
using Sarand.Net.Standard.Base.Utils;
|
|
using Saxonite.Net.Standard.Base.App;
|
|
using Saxonite.Net.Standard.Base.Bus;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Saxonite.Net.Standard.Base.Consoles
|
|
{
|
|
//=======================================================================
|
|
// The index data is intended to provide a common, performance effective route
|
|
// to identifying the activities that are relevant to a User or other context
|
|
// that defines at least one region/sport combination and an effective date (usually today).
|
|
//=======================================================================
|
|
public abstract class SaxActivityConsole : SaErrorStateItem
|
|
{
|
|
//-------------------------------------------------------------------
|
|
// Definitions.
|
|
/// <summary>
|
|
/// Parameters required to query the index for activities to identify relevant activities.
|
|
/// </summary>
|
|
public class IndexContext
|
|
{
|
|
// ToDo Include Localiser.
|
|
/// <summary>
|
|
/// Index Context - high level activity filter.
|
|
/// <para>User Account allows User specific information about the activities to be included.</para>
|
|
/// </summary>
|
|
public IndexContext(SysId userAccountId)
|
|
{
|
|
UserAccountId = userAccountId;
|
|
}
|
|
public SysId UserAccountId { get; }
|
|
/// <summary>Activities must match one of the sport/region combinations specified.</summary>
|
|
public List<SaxActivityIndex.SportRegionIds> SportRegionIdsIncluded { get; } = new List<SaxActivityIndex.SportRegionIds>();
|
|
/// <summary>
|
|
/// Owner Users - eg. journalist for articles.
|
|
/// <para>Allows the users' activities to be queried without relying on matching sport/region combinations.</para>
|
|
/// </summary>
|
|
public List<SysId> UserAccountIdsOwner { get; } = new List<SysId>();
|
|
/// <summary>
|
|
/// Owner Organisations - for articles, events and opportunities.
|
|
/// <para>Allows the organisations' own activities to be queried without relying on matching sport/region combinations.</para>
|
|
/// </summary>
|
|
public List<SysId> OrganisationIdsOwner { get; } = new List<SysId>();
|
|
// Todo: Default effective period for Activities.
|
|
public DateTime EffectiveFrom { get; set; } = DateUtil.IncrementDate(DateTime.Today, -365);
|
|
public DateTime EffectiveTo { get; set; } = DateUtil.IncrementDate(DateTime.Today, 30);
|
|
public DateTime NotExpiredOn { get; set; } = DateTime.Today;
|
|
public bool IsValid()
|
|
{
|
|
// Context must contain at least a sport, a region and a valid effective period.
|
|
if (!SportRegionIdsIncluded.Exists(item => SysId.IsValid(item.SportId) && SysId.IsValid(item.RegionId)) && !UserAccountIdsOwner.HasValidIds() && !OrganisationIdsOwner.HasValidIds()) return false;
|
|
if (!DateUtil.IsValid(EffectiveFrom) || EffectiveTo < EffectiveFrom) return false;
|
|
return true;
|
|
}
|
|
public DbQuery.Paging Paging { get; } = new DbQuery.Paging();
|
|
}
|
|
/// <summary>
|
|
/// Activities identified by querying index with context.
|
|
/// </summary>
|
|
public class IndexResults
|
|
{
|
|
public class ActivityData
|
|
{
|
|
public ActivityData(ItemId itemId, DateTime effectiveOn)
|
|
{
|
|
ItemId = itemId;
|
|
EffectiveOn = effectiveOn;
|
|
}
|
|
public ItemId ItemId { get; }
|
|
public DateTime EffectiveOn { get; }
|
|
// Organisation.
|
|
public SysId OrganisationId { get; set; }
|
|
public String Organisation { get; set; }
|
|
public bool OrganisationHasLogo { get; set; }
|
|
// Author.
|
|
public SysId UserAccountIdAuthor { get; set; }
|
|
public String Author { get; set; }
|
|
// Activity details.
|
|
public String Caption { get; protected set; }
|
|
public String Blurb { get; protected set; }
|
|
// Thumbnail.
|
|
public SysId ItemImageIdThumbnail { get; set; }
|
|
// Sport.
|
|
public SysId SportId { get; protected set; }
|
|
public String SportName { get; protected set; }
|
|
// Region.
|
|
public SysId RegionId { get; protected set; }
|
|
public String RegionName { get; protected set; }
|
|
// User Activity.
|
|
public DateTime LastListedAt { get; protected set; }
|
|
public DateTime LastViewedAt { get; protected set; }
|
|
public Sax.ActivityReaction Reaction { get; protected set; }
|
|
public DateTime LastReactedAt { get; protected set; }
|
|
}
|
|
public List<ActivityData> Items { get; } = new List<ActivityData>();
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Data members.
|
|
private SaxInternals internals = null;
|
|
private readonly List<Sax.DataItemType> validActivityItemTypes = new List<Sax.DataItemType>()
|
|
{
|
|
Sax.DataItemType.Article,
|
|
Sax.DataItemType.OrganisationEvent,
|
|
Sax.DataItemType.OrganisationOpportunity,
|
|
};
|
|
|
|
//-------------------------------------------------------------------
|
|
// Protected construction.
|
|
protected SaxActivityConsole(SaxSessionContext sessionContext)
|
|
{
|
|
SessionContext = sessionContext;
|
|
}
|
|
protected override void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
if (internals != null) internals.Dispose(); internals = null;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Properties.
|
|
protected SaxSessionContext SessionContext { get; }
|
|
protected SaxInternals Internals { get { if (internals == null) internals = new SaxInternals(SessionContext); return internals; } }
|
|
protected ISacsDatabase CoreDatabase { get { return Internals.CoreDatabase; } }
|
|
protected List<Sax.DataItemType> ValidActivityItemTypes { get { return validActivityItemTypes.ToList(); } }
|
|
|
|
//-------------------------------------------------------------------
|
|
// Query Activity Index Entries for User Context.
|
|
//-------------------------------------------------------------------
|
|
public abstract IndexResults QueryIndex(IndexContext context);
|
|
|
|
//-------------------------------------------------------------------
|
|
// Store Activity Index for Specific activities.
|
|
//-------------------------------------------------------------------
|
|
/// <summary>
|
|
/// Store the Activity Index for an Article.
|
|
/// </summary>
|
|
public bool StoreActivityIndex(SaxArticle article, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
ClearErrorState();
|
|
|
|
// Determine whether article should be included in the Activity Index.
|
|
bool includeInActivityIndex = true;
|
|
|
|
// Only published articles have an activity index.
|
|
if (!DateUtil.IsValid(article.PublishedAt)) includeInActivityIndex = false;
|
|
|
|
// Only active articles have an activity index.
|
|
if (!article.IsStatusActive) includeInActivityIndex = false;
|
|
|
|
// NB There will be other rules as well, eg. whether expired.
|
|
|
|
if (includeInActivityIndex)
|
|
{
|
|
// Activity Index properties.
|
|
IndexData indexData = new IndexData(article.GetItemId());
|
|
indexData.UserAccountIdOwner = article.UserAccountIdAuthor;
|
|
indexData.OrganisationIdOwner = article.OrganisationId;
|
|
indexData.SportIds.Add(article.SportIdPrimary);
|
|
indexData.RegionIds.Add(article.RegionIdPrimary);
|
|
indexData.EffectiveOn = DateUtil.OnInvalid(article.PublishedAt?.Date, article.CreateStamp.On.Date);
|
|
return StoreActivityIndexData(indexData, dbUpdateInfo);
|
|
}
|
|
return ClearActivityIndex(article.GetItemId(), dbUpdateInfo);
|
|
}
|
|
public bool ClearActivityIndex(SaxArticle article, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
return ClearActivityIndex(article.GetItemId(), dbUpdateInfo);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
/// <summary>
|
|
/// Store the Activity Index for a Organisation Event.
|
|
/// </summary>
|
|
public bool StoreActivityIndex(SaxOrganisationEvent organisationEvent, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
ClearErrorState();
|
|
|
|
// Only active opportunities have an activity index.
|
|
if (!organisationEvent.IsStatusActive) ClearActivityIndex(organisationEvent.GetItemId(), dbUpdateInfo);
|
|
|
|
// NB There will be other rules as well, eg. whether published.
|
|
|
|
// Activity Index properties.
|
|
IndexData indexData = new IndexData(organisationEvent.GetItemId());
|
|
indexData.OrganisationIdOwner = organisationEvent.OrganisationId;
|
|
indexData.SportIds.Add(organisationEvent.SportIdPrimary);
|
|
indexData.RegionIds.Add(organisationEvent.RegionIdCountry);
|
|
indexData.EffectiveOn = DateUtil.OnInvalid(organisationEvent.PublishedAt?.Date, organisationEvent.CreateStamp.On.Date);
|
|
indexData.ExpiresOn = DateUtil.OnInvalid(organisationEvent.ExpiresAt?.Date, DateUtil.IncrementDate(indexData.EffectiveOn, 7));
|
|
return StoreActivityIndexData(indexData, dbUpdateInfo);
|
|
}
|
|
public bool ClearActivityIndex(SaxOrganisationEvent organisationEvent, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
return ClearActivityIndex(organisationEvent.GetItemId(), dbUpdateInfo);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
/// <summary>
|
|
/// Store the Activity Index for a Organisation Opportunity.
|
|
/// </summary>
|
|
public bool StoreActivityIndex(SaxOrganisationOpportunity opportunity, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
ClearErrorState();
|
|
|
|
// Only active opportunities have an activity index.
|
|
if (!opportunity.IsStatusActive) ClearActivityIndex(opportunity.GetItemId(), dbUpdateInfo);
|
|
|
|
// NB There will be other rules as well, eg. whether published.
|
|
|
|
// Activity Index properties.
|
|
IndexData indexData = new IndexData(opportunity.GetItemId());
|
|
indexData.OrganisationIdOwner = opportunity.OrganisationId;
|
|
indexData.SportIds.Add(opportunity.SportIdPrimary);
|
|
indexData.RegionIds.Add(opportunity.RegionIdPrimary);
|
|
indexData.EffectiveOn = DateUtil.OnInvalid(opportunity.PublishedAt?.Date, opportunity.CreateStamp.On.Date);
|
|
indexData.ExpiresOn = DateUtil.OnInvalid(opportunity.ExpiresAt?.Date, DateUtil.IncrementDate(indexData.EffectiveOn, 28));
|
|
return StoreActivityIndexData(indexData, dbUpdateInfo);
|
|
}
|
|
public bool ClearActivityIndex(SaxOrganisationOpportunity opportunity, DbUpdateInfo dbUpdateInfo)
|
|
{
|
|
return ClearActivityIndex(opportunity.GetItemId(), dbUpdateInfo);
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Store Activity Index.
|
|
//-------------------------------------------------------------------
|
|
/// <summary>Data values that make up the index for an activity.</summary>
|
|
protected class IndexData
|
|
{
|
|
public IndexData(ItemId itemId)
|
|
{
|
|
ItemId = itemId;
|
|
}
|
|
public ItemId ItemId { get; }
|
|
public SysId UserAccountIdOwner { get; set; }
|
|
public SysId OrganisationIdOwner { get; set; }
|
|
public List<SysId> SportIds { get; } = new List<SysId>();
|
|
public List<SysId> RegionIds { get; } = new List<SysId>();
|
|
public DateTime EffectiveOn { get; set; }
|
|
public DateTime ExpiresOn { get; set; }
|
|
public bool IsValid()
|
|
{
|
|
if (!ItemId.IsValid(ItemId)) return false;
|
|
if (!SportIds.HasValidIds()) return false;
|
|
if (!RegionIds.HasValidIds()) return false;
|
|
if (!DateUtil.IsValid(EffectiveOn)) return false;
|
|
return true;
|
|
}
|
|
}
|
|
/// <summary>Single entry in the index for an activity.</summary>
|
|
protected class IndexEntryData
|
|
{
|
|
public IndexEntryData(ItemId itemId, SysId userAccountIdOwner, SysId organisationIdOwner, SysId sportId, SysId regionId, DateTime effectiveOn, DateTime expiresOn)
|
|
{
|
|
ItemId = itemId;
|
|
UserAccountIdOwner = userAccountIdOwner;
|
|
OrganisationIdOwner = organisationIdOwner;
|
|
SportId = sportId;
|
|
RegionId = regionId;
|
|
EffectiveOn = effectiveOn;
|
|
ExpiresOn = expiresOn;
|
|
}
|
|
public ItemId ItemId { get; }
|
|
public SysId UserAccountIdOwner { get; }
|
|
public SysId OrganisationIdOwner { get; }
|
|
public SysId SportId { get; }
|
|
public SysId RegionId { get; }
|
|
public DateTime EffectiveOn { get; }
|
|
public DateTime? ExpiresOn { get; }
|
|
public bool IsValid()
|
|
{
|
|
if (!ItemId.IsValid(ItemId)) return false;
|
|
if (!SysId.IsValid(SportId)) return false;
|
|
if (!SysId.IsValid(RegionId)) return false;
|
|
if (!DateUtil.IsValid(EffectiveOn)) return false;
|
|
return true;
|
|
}
|
|
/// <summary>Compare index entry Ids - Item, Sport & Region.</summary>
|
|
public bool MatchesIds(SaxActivityIndex activityIndex)
|
|
{
|
|
if (!ItemId.Equals(activityIndex.ItemId)) return false;
|
|
if (!SportId.Equals(activityIndex.SportId)) return false;
|
|
if (!RegionId.Equals(activityIndex.RegionId)) return false;
|
|
return true;
|
|
}
|
|
/// <summary>Compare index entry Ids - Item, Sport & Region - and effective date.</summary>
|
|
public bool Matches(SaxActivityIndex activityIndex)
|
|
{
|
|
if (!MatchesIds(activityIndex)) return false;
|
|
if (!EffectiveOn.Equals(activityIndex.EffectiveOn)) return false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// Activity Index data.
|
|
protected abstract bool StoreActivityIndexData(IndexData indexData, DbUpdateInfo dbUpdateInfo);
|
|
protected abstract bool ClearActivityIndex(ItemId itemId, DbUpdateInfo dbUpdateInfo);
|
|
|
|
//-------------------------------------------------------------------
|
|
// Activity Index Utilities.
|
|
protected List<IndexEntryData> GetEntriesForIndex(IndexData indexData)
|
|
{
|
|
ClearErrorState();
|
|
List<IndexEntryData> indexEntries = new List<IndexEntryData>();
|
|
if (ItemId.IsValid(indexData.ItemId) && DateUtil.IsValid(indexData.EffectiveOn))
|
|
{
|
|
foreach (SysId sportId in indexData.SportIds.FindAll(item => SysId.IsValid(item)))
|
|
{
|
|
foreach (SysId regionId in indexData.RegionIds.FindAll(item => SysId.IsValid(item)))
|
|
{
|
|
IndexEntryData indexEntry = new IndexEntryData(indexData.ItemId, indexData.UserAccountIdOwner, indexData.OrganisationIdOwner, sportId, regionId, indexData.EffectiveOn, indexData.ExpiresOn);
|
|
if (indexEntry.IsValid())
|
|
indexEntries.Add(indexEntry);
|
|
}
|
|
}
|
|
}
|
|
return indexEntries;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
// User Activities
|
|
//-------------------------------------------------------------------
|
|
public abstract bool RecordUserActivitiesListed(SysId userAccountId, List<ItemId> activityItemIds, DbUpdateInfo dbUpdateInfo);
|
|
public abstract bool RecordUserActivityViewed(SysId userAccountId, ItemId activityItemId, DbUpdateInfo dbUpdateInfo);
|
|
public abstract bool RecordUserActivityReaction(SysId userAccountId, ItemId activityItemId, Sax.ActivityReaction activityReaction, DbUpdateInfo dbUpdateInfo);
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|