using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Diagnostics; 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.Utils; using Saxonite.Net.Core.Web.Online.Models; using Saxonite.Net.Standard.Base.App; using Saxonite.Net.Standard.Base.Bus; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Saxonite.Net.Core.Web.Online.Controllers { //======================================================================= // Online Organisation Controller - Events - Ajax actions. //======================================================================= partial class OrganisationController { //------------------------------------------------------------------- // Organisation Event data. private class EventListData : AjaxResponse_Data.ItemData_Base { public String EventAtDateFmt { get; set; } public String EventAtTimeFmt { get; set; } public String EventToDateFmt { get; set; } public String EventToTimeFmt { get; set; } public String Duration { get; set; } public String TypeCode { get; set; } public String TypeDesc { get; set; } public String Summary { get; set; } public String SportCaptionPrimary { get; set; } public String RegionCaptionCountry { get; set; } public String PublishedOnFmt { get; set; } public String ExpiresOnFmt { get; set; } } private class EventItemData : EventListData { public String EventAt_Calendar { get; set; } public String EventAt_YYYYMMDD { get; set; } public String EventAt_HHMM { get; set; } public String EventTo_Calendar { get; set; } public String EventTo_YYYYMMDD { get; set; } public String EventTo_HHMM { get; set; } public String Details { get; set; } public String SportIdPrimary { get; set; } public String RegionIdCountry { get; set; } public String PublishedOn_YYYYMMDD { get; set; } public String ExpiresOn_YYYYMMDD { get; set; } } private void PopulateEventResponseListData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventListData data) { data.Id = model.EncryptId(organisationEvent.Id); // 'At' date/time. data.EventAtDateFmt = Localiser.FormatDate(organisationEvent.EventAt); if (organisationEvent.HasValidEventAtTime()) data.EventAtTimeFmt = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); // 'To' date/time. data.EventToDateFmt = Localiser.FormatDate(organisationEvent.EventTo); if (organisationEvent.HasValidEventToTime()) data.EventToTimeFmt = DateUtil.Format(organisationEvent.EventTo, "HH:mm"); // Event properties. if (DateUtil.IsValid(organisationEvent.EventTo) && organisationEvent.EventTo > organisationEvent.EventAt) data.Duration = DateUtil.FormatNumberOfSeconds(((DateTime)organisationEvent.EventTo - organisationEvent.EventAt).TotalSeconds); data.TypeCode = EventTypeCodes.GetCodeForType(organisationEvent.EventType); data.TypeDesc = Localiser.GetEventTypeCaption(organisationEvent.EventType); data.Summary = organisationEvent.Summary; data.SportCaptionPrimary = model.GetSportCaption(organisationEvent.SportIdPrimary); data.RegionCaptionCountry = model.GetRegionCaption(organisationEvent.RegionIdCountry); data.CreatedOnFmt = Localiser.FormatDate(organisationEvent.CreateStamp.On); if (DateUtil.IsValid(organisationEvent.PublishedAt)) data.PublishedOnFmt = Localiser.FormatDate(organisationEvent.PublishedAt); if (DateUtil.IsValid(organisationEvent.ExpiresAt)) data.ExpiresOnFmt = Localiser.FormatDate(organisationEvent.ExpiresAt); data.StatusCode = organisationEvent.StatusCode; data.StatusDesc = organisationEvent.StatusDesc; } private void PopulateEventResponseItemData(Model_Organisation_Events model, SaxOrganisationEvent organisationEvent, EventItemData data) { PopulateEventResponseListData(model, organisationEvent, data as EventListData); // 'At' date/time. data.EventAt_Calendar = model.FormatDateForForm(organisationEvent.EventAt); data.EventAt_YYYYMMDD = DateUtil.Format(organisationEvent.EventAt, "yyyyMMdd"); if (organisationEvent.HasValidEventAtTime()) data.EventAt_HHMM = DateUtil.Format(organisationEvent.EventAt, "HH:mm"); // 'To' date/time. data.EventTo_Calendar = model.FormatDateForForm(organisationEvent.EventTo); data.EventTo_YYYYMMDD = DateUtil.Format(organisationEvent.EventTo, "yyyyMMdd"); if (organisationEvent.HasValidEventToTime()) data.EventTo_HHMM = DateUtil.Format(organisationEvent.EventTo, "HH:mm"); // Event properties. data.Details = organisationEvent.Details; data.RegionIdCountry = model.GetEncryptedRegionId(organisationEvent.RegionIdCountry); data.SportIdPrimary = model.GetEncryptedSportId(organisationEvent.SportIdPrimary); if (DateUtil.IsValid(organisationEvent.PublishedAt)) data.PublishedOn_YYYYMMDD = DateUtil.Format(organisationEvent.PublishedAt, "yyyyMMdd"); if (DateUtil.IsValid(organisationEvent.ExpiresAt)) data.ExpiresOn_YYYYMMDD = DateUtil.Format(organisationEvent.ExpiresAt, "yyyyMMdd"); } //------------------------------------------------------------------- // Get Event List ajax request. //------------------------------------------------------------------- private class AjaxResponse_EventList : AjaxResponse_Data { // Construction. public AjaxResponse_EventList(SaxModel_Online model) : base(model) { } // Event list. public List Events { get; } = new List(); // User profile. public class UserData { public bool CanManage { get; set; } } public UserData User { get; } = new UserData(); // Organisation. public class OrganisationData { public String Id { get; set; } public String Name { get; set; } public String SportId { get; set; } public String SportName { get; set; } public String RegionId { get; set; } public String RegionName { get; set; } } public OrganisationData Organisation { get; } = new OrganisationData(); // Reference data. public List EventTypes { get; } = new List(); public String EventTypeDefault { get; set; } } //------------------------------------------------------------------- [HttpPost] [Route("Organisation/Ajax/GetEventList")] [Route("Organisation/Ajax/GetEvents")] public IActionResult Ajax_GetEventList(Model_Organisation_Events model) { String fn = GetType().Name + ".Ajax_GetEventList"; String messageTitle = Localiser["organisation.caption.events"]; AjaxResponse_EventList responseData = new AjaxResponse_EventList(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); RefreshModel(model); SysId userAccountId = SessionUserAccountId; // Record disposable items as they are created so all can be disposed when needed. using (DisposableCollection disposableItems = new DisposableCollection()) { // Organisation. SysId organisationId = model.ExtractSysId(model.Filter.OrganisationId); SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId); disposableItems.Add(organisation); if (organisation == null || !organisation.IsStatusActive) { SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event list. OrganisationId: '" + model.Filter.OrganisationId + "'"); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"])); } if (organisation != null) { // Store filter data. SessionData_Online.Filter.SetMemberOrganisation(organisation); // Reference data - organisationEvent types. foreach (TypeCodeDesc eventType in EventTypeCodes) responseData.EventTypes.Add(eventType.Code, Localiser.GetEventTypeCaption((Sax.EventType)eventType.Type)); // ToDo: Organisation default Event Type. responseData.EventTypeDefault = EventTypeCodes.GetCodeForType(Sax.EventType.Playing); // User organisation. SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params(); prmUserOrganisation.UserAccountIdsIncluded.Add(userAccountId); prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId); prmUserOrganisation.UserAccountStatusCat = SaxUserAccount.StatusCat.ActiveOnly; prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly; SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation); disposableItems.Add(userOrganisation); if (userOrganisation == null) { SaLogger.Warn(fn + " Invalid/inactive user organisation for Event list. UserAccountId: " + SysId.ToString(userAccountId) + ". OrganisationId: " + model.Filter.OrganisationId + "."); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"])); } // Organisation. responseData.Organisation.Id = SysId.ToString(organisation.Id); responseData.Organisation.Name = organisation.Name; responseData.Organisation.SportId = model.GetEncryptedSportId(organisation.SportIdPrimary); responseData.Organisation.SportName = model.GetSportCaption(organisation.SportIdPrimary); responseData.Organisation.RegionId = model.GetEncryptedRegionId(organisation.RegionIdPrimary); responseData.Organisation.RegionName = model.GetRegionCaption(organisation.RegionIdPrimary); // User details. responseData.User.CanManage = userOrganisation.CanManageSchedule; // Item filter. SaxOrganisationEvent.Params prmEvent = new SaxOrganisationEvent.Params(); prmEvent.UserAccountIdsIncluded.Add(userAccountId); prmEvent.OrganisationIdsIncluded.Add(organisationId); switch (model.Filter.Period.PeriodType) { case Model_Organisation_Events.PeriodType.FromThisMonth: prmEvent.EventFrom = DateUtil.StartOfMonth(DateTime.Today); break; case Model_Organisation_Events.PeriodType.FromLastMonth: prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, -1)); break; case Model_Organisation_Events.PeriodType.FromNextMonth: prmEvent.EventFrom = DateUtil.StartOfMonth(DateUtil.IncrementMonth(DateTime.Today, 1)); break; case Model_Organisation_Events.PeriodType.FromThisWeek: default: prmEvent.EventFrom = DateUtil.StartOfWorkingWeek(DateTime.Today); break; } prmEvent.EventFilter = model.Filter.Event; prmEvent.StatusCat = SaxOrganisationEvent.StatusCat.NotDeleted; prmEvent.SortColumns.Add(ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime)); model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationEventCount(prmEvent); model.PopulatePagingTo(prmEvent.ResultsPaging); // Item columns. ColumnDfn colId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Id); ColumnDfn colEventAt = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventAt_DateTime); ColumnDfn colEventTo = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTo_DateTime); ColumnDfn colEventTypeCode = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.EventTypeCode); ColumnDfn colSummary = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Summary); ColumnDfn colRegionId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.RegionIdCountry); ColumnDfn colRegionName = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Region_Name); ColumnDfn colSportId = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.SportIdPrimary); ColumnDfn colSportName = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Sport_Name); ColumnDfn colPublishedOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.PublishedAt_Date); ColumnDfn colExpiresOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.ExpiresAt_Date); ColumnDfn colStatus = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.Status); ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationEventColumnDfn(SaxOrganisationEvent.Column.CreateOn_Date); List columns = new List() { colId, colEventAt, colEventTo, colEventTypeCode, colSummary, colRegionId, colRegionName, colSportId, colSportName, colPublishedOn, colExpiresOn, colStatus, colCreatedOn }; // Sort columns. colCreatedOn.SortAscending = false; prmEvent.SortColumns.Add(colCreatedOn); // Query items. using (DbResultSet resultSet = ActivityMgr.ExecuteOrganisationEventQuery(columns, prmEvent)) { while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); DateTime eventAt = values.GetDateTime(colEventAt.DataName); DateTime? eventTo = values.GetDateTime(colEventTo.DataName); EventListData eventData = new EventListData() { Id = model.EncryptId(new SysId(values.GetLong(colId.DataName))), EventAtDateFmt = Localiser.FormatDate(values.GetDateTime(colEventAt.DataName)), TypeCode = values.GetString(colEventTypeCode.DataName), TypeDesc = Localiser.GetEventTypeCaption((Sax.EventType)EventTypeCodes.GetTypeForCode(values.GetString(colEventTypeCode.DataName))), Summary = ActivityMgr.GetOrganisationEventDataValue(colSummary, values).AsString(), RegionCaptionCountry = model.GetRegionCaption(SysId.ToSysId(values.GetString(colRegionId.DataName))), SportCaptionPrimary = model.GetSportCaption(SysId.ToSysId(values.GetString(colSportId.DataName))), CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)), PublishedOnFmt = Localiser.FormatDate(values.GetDateTime(colPublishedOn.DataName)), ExpiresOnFmt = Localiser.FormatDate(values.GetDateTime(colExpiresOn.DataName)), StatusCode = values.GetString(colStatus.DataName), StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)) }; if (SaxOrganisationEvent.HasValidEventTime(eventAt)) eventData.EventAtTimeFmt = DateUtil.Format(eventAt, "HH:mm"); if (DateUtil.IsValid(eventTo) && eventAt.Date != ((DateTime)eventTo).Date) eventData.EventToDateFmt = Localiser.FormatDate(eventTo); if (SaxOrganisationEvent.HasValidEventTime(eventTo)) eventData.EventToTimeFmt = DateUtil.Format(eventTo, "HH:mm"); if (DateUtil.IsValid(eventTo) && eventTo > eventAt) eventData.EventAtTimeFmt = DateUtil.FormatNumberOfSeconds(((DateTime)eventTo - eventAt).TotalSeconds); responseData.Events.Add(eventData); } } } } if (model.Paging.IsPaged) model.Paging.ItemCount = (ushort)responseData.Events.Count; // Complete response. responseData.SetPaging(model); responseData.Success = true; return Json(responseData); } //------------------------------------------------------------------- // Get Event ajax request. //------------------------------------------------------------------- private class AjaxResponse_Event : AjaxResponse_Data { // Construction. public AjaxResponse_Event(SaxModel_Online model) : base(model) { } // Event details. public EventItemData Event { get; } = new EventItemData(); } //------------------------------------------------------------------- [HttpPost] [Route("Organisation/Ajax/GetEvent")] public IActionResult Ajax_GetEvent(Model_Organisation_Events model) { String fn = GetType().Name + ".Ajax_GetEvent"; String messageTitle = Localiser["organisation.caption.event"]; AjaxResponse_Event responseData = new AjaxResponse_Event(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); RefreshModel(model); // Record disposable items as they are created so all can be disposed when needed. using (DisposableCollection disposableItems = new DisposableCollection()) { // Identify item. SysId eventId = model.ExtractSysId(model.EventId); if (!SysId.IsValid(eventId)) return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.specified"])); // Retrieve item. SaxOrganisationEvent organisationEvent = ActivityMgr.GetOrganisationEventById(eventId); disposableItems.Add(organisationEvent); if (organisationEvent == null) { SaLogger.Warn(fn + " Failed to retrieve Organisation Event for Id: '" + model.EventId + "'"); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); } // Validate organisation. SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationEvent.OrganisationId); disposableItems.Add(organisation); if (organisation == null || !organisation.IsStatusActive) { SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event. OrganisationId: '" + organisationEvent.OrganisationId + "'"); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"])); } // Make a note of the selected Organisation. SessionData_Online.Filter.SetMemberOrganisation(organisation); // Construct response. PopulateEventResponseItemData(model, organisationEvent, responseData.Event); } // Complete response. responseData.Success = true; return Json(responseData); } //------------------------------------------------------------------- // Store Event ajax request. //------------------------------------------------------------------- [HttpPost] [Route("Organisation/Ajax/StoreEvent")] public IActionResult Ajax_StoreEvent(Model_Organisation_Events model) { String fn = GetType().Name + ".Ajax_StoreEvent"; String messageTitle = Localiser["organisation.caption.event"]; AjaxResponse_Event responseData = new AjaxResponse_Event(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData); RefreshModel(model); // Record disposable items as they are created so all can be disposed when needed. using (DisposableCollection disposableItems = new DisposableCollection()) { // Validate item properties. model.ValidateEventData(responseData); if (responseData.HasControlErrors()) return Json(responseData); // Validate Event against Id against 'Exists' flag. SysId eventId = model.ExtractSysId(model.EventId); bool eventExists = StringUtil.ToBool(model.EventExists); if (eventExists && !SysId.IsValid(eventId)) { SaLogger.Warn(fn + " Id not specified for existing Event."); return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"])); } if (!eventExists && SysId.IsValid(eventId)) { SaLogger.Warn(fn + " Id specified for new Event: '" + model.EventId + "'"); return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"])); } // Retrieve existing item. SaxOrganisationEvent organisationEvent = ActivityMgr.GetOrganisationEventById(eventId); disposableItems.Add(organisationEvent); if (organisationEvent == null && SysId.IsValid(eventId)) { SaLogger.Warn(fn + " Failed to retrieve organisationEvent for Id: '" + model.EventId + "'"); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); } // Validate the Organisation. SysId organisationId = model.ExtractSysId(model.EventOrganisationId); if (!SysId.IsValid(organisationId)) { SaLogger.Warn(fn + " Organisation Id not specified for Event."); return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"])); } SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId); disposableItems.Add(organisation); if (organisation == null || !organisation.IsStatusActive) { SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Event. OrganisationId: '" + model.EventOrganisationId + "'"); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.system"])); } if (organisationEvent != null && !organisationEvent.OrganisationId.Equals(organisationId)) { SaLogger.Warn(fn + " Inconsistent Organisation Id specified for Event. Expected: " + organisationEvent.OrganisationId + ". Found: " + organisationId); return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"])); } // Ensure that the user has the correct role to update Events for this organisation. if (!AccountMgr.UserHasAnyOrganisationRole(SessionUserAccountId, organisationId, new[] { Sax.OrganisationRole.Admin, Sax.OrganisationRole.ScheduleAdmin })) { SaLogger.Warn(fn + " User doesn't have 'Event Admin' role for Organisation Id: " + organisationId); return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"])); } // Create new item if required. if (organisationEvent == null) { organisationEvent = ActivityMgr.CreateOrganisationEvent(organisationId); disposableItems.Add(organisationEvent); } // Populate item properties. if (model.EventSportIdPrimary != null) organisationEvent.SportIdPrimary = model.ExtractSysId(model.EventSportIdPrimary); if (model.EventRegionIdCountry != null) organisationEvent.RegionIdCountry = model.ExtractSysId(model.EventRegionIdCountry); if (model.EventAtDate != null) { // 'At' date. organisationEvent.EventAt = model.ParseDateFromForm(model.EventAtDate); if (model.EventAtTimeSet && !StringUtil.IsBlank(model.EventAtTime)) { // For midnight (00:00) set +1 minute so that the value is treated as a valid start time. if (model.EventAtTime.Equals("00:00")) model.EventAtTime = "00:01"; organisationEvent.EventAt = DateUtil.SetTime(organisationEvent.EventAt, DateUtil.ParseExact(model.EventAtTime, "HH:mm")); } if (model.EventToDateSet || model.EventToTimeSet) { // 'To' date. organisationEvent.EventTo = organisationEvent.EventAt; if (model.EventToDate != null && model.EventToDateSet) organisationEvent.EventTo = model.ParseDateFromForm(model.EventToDate); // 'To' time. if (model.EventAtTimeSet && model.EventToTimeSet && !StringUtil.IsBlank(model.EventToTime)) { // For midnight (00:00) set +1 minute so that the value is treated as a valid finish time. if (model.EventToTime.Equals("00:00")) model.EventToTime = "00:01"; organisationEvent.EventTo = DateUtil.SetTime(organisationEvent.EventTo ?? organisationEvent.EventAt, DateUtil.ParseExact(model.EventToTime, "HH:mm")); } } else organisationEvent.EventTo = null; } if (model.EventTypeCode != null) organisationEvent.EventType = (Sax.EventType)EventTypeCodes.GetTypeForCode(model.EventTypeCode); if (model.EventSummary != null) organisationEvent.Summary = model.EventSummary; if (model.EventDetails != null) organisationEvent.Details = model.EventDetails; if (model.EventStatusCode != null) organisationEvent.Status = model.EventStatus; // Store item. bool eventCreated = false; if (!SysId.IsValid(organisationEvent.Id)) { if (!ActivityMgr.InsertOrganisationEvent(organisationEvent, DbUpdateInfo)) { SaLogger.Warn(fn + " Failed to insert organisationEvent: " + ActivityMgr.ErrorStateMessage); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.insert.failed"])); } eventCreated = true; } else { if (!ActivityMgr.UpdateOrganisationEvent(organisationEvent, DbUpdateInfo)) { SaLogger.Warn(fn + " Failed to update organisationEvent [Id:" + SysId.ToString(organisationEvent.Id) + "]: " + ActivityMgr.ErrorStateMessage); return Json(responseData.SetPopupMessage(messageTitle, Localiser["msg.error.item.update.failed"])); } } SaLogger.Info(fn + " Event " + (eventCreated ? "created" : "updated") + ". Id: " + organisationEvent.Id.ToString() + ". User: " + SessionData.User.EmailAddress + ". Organisation: " + organisation.Name, true); // Store Event Activity Index data. ActivityConsole.StoreActivityIndex(organisationEvent, DbUpdateInfo); // Construct response. PopulateEventResponseItemData(model, organisationEvent, responseData.Event); } // Complete response. responseData.Success = true; return Json(responseData); } //------------------------------------------------------------------- } //======================================================================= }