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. /// /// Parameters required to query the index for activities to identify relevant activities. /// public class IndexContext { // ToDo Include Localiser. public IndexContext (SysId userAccountId) { UserAccountId = userAccountId; } public SysId UserAccountId { get; } public List SportIds { get; } = new List(); public List RegionIds { get; } = new List(); // Default period is ~12 months ago up to ~3 months in the future. public DateTime EffectiveFrom { get; } = DateUtil.IncrementDate(DateTime.Today, -365); public DateTime EffectiveTo { get; } = DateUtil.IncrementDate(DateTime.Today, 30); public bool IsValid() { // Context must contain at least a sport, a region and a valid effective period. if (!SportIds.HasValidIds()) return false; if (!RegionIds.HasValidIds()) return false; if (!DateUtil.IsValid(EffectiveFrom) || EffectiveTo < EffectiveFrom) return false; return true; } public DbQuery.Paging Paging { get; } = new DbQuery.Paging(); } /// /// Activities identified by querying index with context. /// public class IndexResults { public class ActivityData { public ActivityData(ItemId itemId, DateTime effectiveOn) { ItemId = itemId; EffectiveOn = effectiveOn; } public ItemId ItemId { get; } public DateTime EffectiveOn { get; } public SysId OrganisationId { get; set; } public String Organisation { get; set; } public SysId UserAccountIdAuthor { get; set; } public String Author { get; set; } public String Caption { get; protected set; } public String Blurb { get; protected set; } public SysId SportId { get; protected set; } public String SportName { get; protected set; } 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 Items { get; } = new List(); } //------------------------------------------------------------------- // Data members. private SaxInternals internals = null; private readonly List validActivityItemTypes = new List() { 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 List ValidActivityItemTypes { get { return validActivityItemTypes.ToList(); } } //------------------------------------------------------------------- // Query Activity Index Entries for User Context. //------------------------------------------------------------------- public abstract IndexResults QueryIndex(IndexContext context); //------------------------------------------------------------------- // Store Activity Index for Specific activities. //------------------------------------------------------------------- /// /// Store the Activity Index for an Article. /// 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.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); } //------------------------------------------------------------------- /// /// Store the Activity Index for a Organisation Event. /// 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.SportIds.Add(organisationEvent.SportIdPrimary); indexData.RegionIds.Add(organisationEvent.RegionIdCountry); indexData.EffectiveOn = DateUtil.OnInvalid(organisationEvent.PublishedAt.Date, organisationEvent.CreateStamp.On.Date); return StoreActivityIndexData(indexData, dbUpdateInfo); } public bool ClearActivityIndex(SaxOrganisationEvent organisationEvent, DbUpdateInfo dbUpdateInfo) { return ClearActivityIndex(organisationEvent.GetItemId(), dbUpdateInfo); } //------------------------------------------------------------------- /// /// Store the Activity Index for a Organisation Opportunity. /// 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.SportIds.Add(opportunity.SportIdPrimary); indexData.RegionIds.Add(opportunity.RegionIdPrimary); indexData.EffectiveOn = DateUtil.OnInvalid(opportunity.PublishedAt.Date, opportunity.CreateStamp.On.Date); return StoreActivityIndexData(indexData, dbUpdateInfo); } public bool ClearActivityIndex(SaxOrganisationOpportunity opportunity, DbUpdateInfo dbUpdateInfo) { return ClearActivityIndex(opportunity.GetItemId(), dbUpdateInfo); } //------------------------------------------------------------------- // Store Activity Index. //------------------------------------------------------------------- /// Data values that make up the index for an activity. protected class IndexData { public IndexData(ItemId itemId) { ItemId = itemId; } public ItemId ItemId { get; } public List SportIds { get; } = new List(); public List RegionIds { get; } = new List(); public DateTime EffectiveOn { 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; } } /// Single entry in the index for an activity. protected class IndexEntryData { public IndexEntryData(ItemId itemId, SysId sportId, SysId regionId, DateTime effectiveOn) { ItemId = itemId; SportId = sportId; RegionId = regionId; EffectiveOn = effectiveOn; } public ItemId ItemId { get; } public SysId SportId { get; } public SysId RegionId { get; } public DateTime EffectiveOn { 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; } /// Compare index entry Ids - Item, Sport & Region. 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; } /// Compare index entry Ids - Item, Sport & Region - and effective date. 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 GetEntriesForIndex(IndexData indexData) { ClearErrorState(); List indexEntries = new List(); 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, sportId, regionId, indexData.EffectiveOn); if (indexEntry.IsValid()) indexEntries.Add(indexEntry); } } } return indexEntries; } //------------------------------------------------------------------- // User Activities //------------------------------------------------------------------- public abstract bool RecordUserActivitiesListed(SysId userAccountId, List 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); //------------------------------------------------------------------- } //======================================================================= }