From dc431e1634d1188e74820a82c8516131ef89c99e Mon Sep 17 00:00:00 2001 From: Andy Howard Date: Sat, 16 Jul 2022 13:30:57 +0100 Subject: [PATCH] v1.2.8 --- SaxoniteCoreWeb/Base/App/SaxLocaliser.cs | 6 + .../Base/Controllers/SaxController_Base.cs | 1 + SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs | 1 + .../HomeController-Ajax-ApplicationStats.cs | 2 +- .../Admin/Controllers/HomeController.cs | 2 +- ...OrganisationController-Ajax-Activation.cs} | 8 +- ...rganisationController-Ajax-Associations.cs | 619 ++++++++++++++++++ ...=> OrganisationController-Ajax-Members.cs} | 34 +- .../OrganisationController-Ajax.cs | 6 +- .../OrganisationController-Images-Ajax.cs | 6 +- .../Controllers/OrganisationController.cs | 31 +- .../Admin/Controllers/SaxController_Admin.cs | 22 +- .../Controllers/SecurityController-Ajax.cs | 2 +- .../Admin/Controllers/UserController-Ajax.cs | 28 +- .../Controllers/UsersOnlineController-Ajax.cs | 18 +- .../Models/Model_OrganisationAssociations.cs | 156 +++++ .../Admin/Models/Model_OrganisationMembers.cs | 5 +- .../Localisation/SaxAdminProperties.resx | 57 +- .../Views/Organisation/Associations.cshtml | 116 ++++ .../Views/Organisation/Index.cshtml | 21 +- .../Views/Organisation/Members.cshtml | 8 +- ...l => Panel-Organisation-Activation.cshtml} | 0 ...html => Panel-Organisation-Address.cshtml} | 0 .../Panel-Organisation-Association.cshtml | 81 +++ ...shtml => Panel-Organisation-Dialog.cshtml} | 0 ...shtml => Panel-Organisation-Images.cshtml} | 0 ...shtml => Panel-Organisation-Member.cshtml} | 6 +- .../Views/Shared/_Layout.cshtml | 2 +- SaxoniteCoreWebAdmin/wwwroot/css/sax-data.css | 5 + .../wwwroot/img/action/network-16.png | Bin 0 -> 362 bytes .../wwwroot/img/action/network-24.png | Bin 0 -> 525 bytes .../wwwroot/img/action/network-32.png | Bin 0 -> 743 bytes SaxoniteCoreWebAdmin/wwwroot/js/sax-main.js | 10 +- .../wwwroot/js/sax-org-add.js | 2 +- .../wwwroot/js/sax-org-ass.js | 217 ++++++ .../wwwroot/js/sax-org-mbr.js | 3 +- SaxoniteCoreWebAdmin/wwwroot/js/sax-org.js | 27 +- .../Localisation/SaxOnlineProperties.resx | 12 +- .../Online/Controllers/HomeController.cs | 2 +- .../Controllers/SaxController_Online.cs | 21 +- .../Controllers/SecurityController-Ajax.cs | 2 +- .../Common/OrganisationControls-Core.cshtml | 4 +- .../Organisation/Panel-MemberDialog.cshtml | 4 +- .../wwwroot/js/sax-org-req.js | 20 +- .../wwwroot/js/sax-usr-org.js | 10 +- SaxoniteStandardBase/Base/App/Sax-Version.cs | 4 +- SaxoniteStandardBase/Base/App/Sax.cs | 13 + .../Base/App/SaxDbDfn_Core.cs | 294 +++++---- SaxoniteStandardBase/Base/App/SaxInternals.cs | 1 + .../Base/App/SaxSystem-CodeTypes.cs | 8 + .../Base/Bus/SaxItemAssociation.cs | 254 +++++++ .../Base/Bus/SaxOrganisation.cs | 9 + .../Mgr/SaxItemDataMgr-ItemAssociation.cs | 214 ++++++ SaxoniteStandardBase/Base/Mgr/SaxItemMgr.cs | 1 + .../Dbas/Bus/SaxItemAssociation_Dbas.cs | 33 + .../Dbas/Internal/ActivityFeedback_Db.cs | 2 +- .../Dbas/Internal/ActivityIndex_Db.cs | 2 +- .../Dbas/Internal/Article_Db.cs | 2 +- .../Dbas/Internal/Association_Db.cs | 221 +++++++ .../Dbas/Internal/ItemAddress_Db.cs | 2 +- .../Dbas/Internal/ItemAssociation_Db.cs | 230 +++++++ .../Dbas/Internal/ItemImage_Db.cs | 2 +- .../Dbas/Internal/ItemSport_Db.cs | 2 +- .../Dbas/Internal/OrganisationEvent_Db.cs | 2 +- .../Internal/OrganisationOpportunity_Db.cs | 2 +- .../Dbas/Internal/Organisation_Db.cs | 2 +- .../Dbas/Internal/Region_Db.cs | 2 +- .../Dbas/Internal/Sport_Db.cs | 2 +- .../Dbas/Internal/UserAccount_Db.cs | 2 +- .../Dbas/Internal/UserActivity_Db.cs | 2 +- .../Dbas/Internal/UserOnline_Db.cs | 2 +- .../Dbas/Internal/UserOrganisation_Db.cs | 2 +- .../Dbas/Internal/UserRole_Db.cs | 2 +- .../Dbas/Internal/UserSession_Db.cs | 2 +- .../Dbas/Internal/UserSportExperience_Db.cs | 2 +- .../Dbas/Internal/UserSport_Db.cs | 2 +- .../SaxItemDataMgr_Dbas-ItemAssociation.cs | 603 +++++++++++++++++ .../Dbas/Mgr/SaxItemDataMgr_Dbas-ItemSport.cs | 2 +- .../Resources/Database/SaxDbDfn_Core.xml | 378 ++++++++++- 79 files changed, 3570 insertions(+), 310 deletions(-) rename SaxoniteCoreWebAdmin/Admin/Controllers/{OrganisationController-Activation-Ajax.cs => OrganisationController-Ajax-Activation.cs} (97%) create mode 100644 SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Associations.cs rename SaxoniteCoreWebAdmin/Admin/Controllers/{OrganisationController-Members-Ajax.cs => OrganisationController-Ajax-Members.cs} (93%) create mode 100644 SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationAssociations.cs create mode 100644 SaxoniteCoreWebAdmin/Views/Organisation/Associations.cshtml rename SaxoniteCoreWebAdmin/Views/Organisation/{Panel-ActivationDialog.cshtml => Panel-Organisation-Activation.cshtml} (100%) rename SaxoniteCoreWebAdmin/Views/Organisation/{Panel-OrganisationAddressDialog.cshtml => Panel-Organisation-Address.cshtml} (100%) create mode 100644 SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Association.cshtml rename SaxoniteCoreWebAdmin/Views/Organisation/{Panel-OrganisationDialog.cshtml => Panel-Organisation-Dialog.cshtml} (100%) rename SaxoniteCoreWebAdmin/Views/Organisation/{Panel-OrganisationImagesDialog.cshtml => Panel-Organisation-Images.cshtml} (100%) rename SaxoniteCoreWebAdmin/Views/Organisation/{Panel-MemberDialog.cshtml => Panel-Organisation-Member.cshtml} (92%) create mode 100644 SaxoniteCoreWebAdmin/wwwroot/img/action/network-16.png create mode 100644 SaxoniteCoreWebAdmin/wwwroot/img/action/network-24.png create mode 100644 SaxoniteCoreWebAdmin/wwwroot/img/action/network-32.png create mode 100644 SaxoniteCoreWebAdmin/wwwroot/js/sax-org-ass.js create mode 100644 SaxoniteStandardBase/Base/Bus/SaxItemAssociation.cs create mode 100644 SaxoniteStandardBase/Base/Mgr/SaxItemDataMgr-ItemAssociation.cs create mode 100644 SaxoniteStandardDbas/Dbas/Bus/SaxItemAssociation_Dbas.cs create mode 100644 SaxoniteStandardDbas/Dbas/Internal/Association_Db.cs create mode 100644 SaxoniteStandardDbas/Dbas/Internal/ItemAssociation_Db.cs create mode 100644 SaxoniteStandardDbas/Dbas/Mgr/SaxItemDataMgr_Dbas-ItemAssociation.cs diff --git a/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs b/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs index 901aac5..5ff65e8 100644 --- a/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs +++ b/SaxoniteCoreWeb/Base/App/SaxLocaliser.cs @@ -261,6 +261,12 @@ namespace Saxonite.Net.Core.Web.Base.App return GetCodeTypeCaption(Sax.CodeType.OrganisationRole, organisationRole); } + // Association types. + public String GetAssociationTypeCaption(Sax.AssociationType addressType) + { + return GetCodeTypeCaption(Sax.CodeType.AssociationType, addressType); + } + // Address types. public String GetAddressTypeCaption(Sax.AddressType addressType) { diff --git a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs index b853e59..ea91ac7 100644 --- a/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs +++ b/SaxoniteCoreWeb/Base/Controllers/SaxController_Base.cs @@ -121,6 +121,7 @@ namespace Saxonite.Net.Core.Web.Base.Controllers public List OrganisationTypeCodes { get { return Internals.OrganisationTypeCodes; } } public List OrganisationCategoryCodes { get { return Internals.OrganisationCategoryCodes; } } public List OrganisationRoleCodes { get { return Internals.OrganisationRoleCodes; } } + public List AssociationTypeCodes { get { return Internals.AssociationTypeCodes; } } public List AddressTypeCodes { get { return Internals.AddressTypeCodes; } } public List ContactMethodCodes { get { return Internals.ContactMethodCodes; } } public List EventTypeCodes { get { return Internals.EventTypeCodes; } } diff --git a/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs b/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs index 472f1b5..2b2c9b7 100644 --- a/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs +++ b/SaxoniteCoreWeb/Base/Models/SaxModel_Base.cs @@ -97,6 +97,7 @@ namespace Saxonite.Net.Core.Web.Base.Models public List OrganisationTypeCodes { get { return Internals.OrganisationTypeCodes; } } public List OrganisationCategoryCodes { get { return Internals.OrganisationCategoryCodes; } } public List OrganisationRoleCodes { get { return Internals.OrganisationRoleCodes; } } + public List AssociationTypeCodes { get { return Internals.AssociationTypeCodes; } } public List AddressTypeCodes { get { return Internals.AddressTypeCodes; } } public List ContactMethodCodes { get { return Internals.ContactMethodCodes; } } public List EventTypeCodes { get { return Internals.EventTypeCodes; } } diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController-Ajax-ApplicationStats.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController-Ajax-ApplicationStats.cs index f49c3c6..7312e3b 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController-Ajax-ApplicationStats.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController-Ajax-ApplicationStats.cs @@ -65,7 +65,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Captions. responseData.Stats.User.Caption = Localiser["user.caption.users"]; - responseData.Stats.Organisation.Caption = Localiser["organisation.caption.organisations"]; + responseData.Stats.Organisation.Caption = Localiser["caption.organisations"]; // Core Database connection. ISacsDatabase db = SaxGlobals.App.GetCoreDatabase(SessionContext); diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController.cs index eaba101..3812dbd 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/HomeController.cs @@ -40,7 +40,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // NB Only allowed if there isn't a current user session. if (!ValidUserSession && AppConfig.Security.SignIn.KeepLoggedIn.Allowed) { - String encryptedParams = GetRequestCookie(CookieName_KeepLoggedIn); + String encryptedParams = GetRequestCookie(KeepLoggedIn.CookieName); KeepLoggedInParams keepLoggedInParams = ExtractKeepLoggedInParams(encryptedParams); String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", "."); if (SysId.IsValid(keepLoggedInParams.UserAccountId)) diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Activation.cs similarity index 97% rename from SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs rename to SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Activation.cs index 5e6d998..c3ac648 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Activation-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Activation.cs @@ -16,7 +16,7 @@ using System.Threading.Tasks; namespace Saxonite.Net.Core.Web.Admin.Controllers { //======================================================================= - // Controller: Organisation - Activation - Ajax + // Controller: Organisation - Ajax - Activation //======================================================================= partial class OrganisationController { @@ -30,7 +30,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Organisation details. public OrganisationItemData organisation { get; } = new OrganisationItemData(); // Member awaiting activation. - public List Members { get; } = new List(); + public List Members { get; } = new List(); } //------------------------------------------------------------------- [HttpPost] @@ -38,7 +38,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetActivationInfo(Model_Organisation model) { String fn = GetType().Name + ".Ajax_GetActivationInfo"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_OrganisationActivationInfo responseData = new AjaxResponse_OrganisationActivationInfo(model); // Validate session. @@ -108,7 +108,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_Activate(Model_OrganisationActivation model) { String fn = GetType().Name + ".Ajax_Activate"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model); // Validate session. diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Associations.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Associations.cs new file mode 100644 index 0000000..7a4977f --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Associations.cs @@ -0,0 +1,619 @@ +using Microsoft.AspNetCore.Mvc; +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.Admin.Models; +using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using AssociationTypeOption = Saxonite.Net.Core.Web.Admin.Models.Model_OrganisationAssociations.AssociationTypeOption; + +namespace Saxonite.Net.Core.Web.Admin.Controllers +{ + //======================================================================= + // Controller: Organisation - Ajax - Associations + //======================================================================= + partial class OrganisationController + { + //------------------------------------------------------------------- + // Association type combinations. + //------------------------------------------------------------------- + private static readonly String optionLabel_AffiliatedTo = "Affiliated to"; + private static readonly String optionLabel_Affiliate = "Affiliate"; + private static readonly String optionLabel_Partner = "Partner"; + // Associations are between two items (From & To) but in the context of + // displaying associations for an organisation, the organisation may be + // the 'From' item (normal) or the 'To' item (reversed). + private class AssociationTypeData + { + public AssociationTypeData() + { + // No parameter construction - populating association details for individual item (see Populate()). + } + public AssociationTypeData(AssociationTypeOption associationTypeOption) + { + // Population on construction - generic association type definitions, eg. for drop down menu options. + Populate(associationTypeOption); + } + public void Populate(AssociationTypeOption associationTypeOption) + { + // Default labels - option to select association etc. + Type = ((int)associationTypeOption).ToString(); + Label = GetOptionLabel(associationTypeOption); + } + public void Populate(Sax.AssociationType associationType, bool reversed) + { + // Default labels - option to select association etc. + Populate(GetAssociationTypeOption(associationType, reversed)); + } + public void Populate(Sax.AssociationType associationType, bool reversed, String label) + { + // Populate for specific labels, eg. to identify nature of associated organisation. + AssociationTypeOption associationTypeOption = GetAssociationTypeOption(associationType, reversed); + Type = ((int)associationTypeOption).ToString(); + Label = label; + } + // Properties. + public String Type { get; set; } + public String Label { get; set; } + // Utilities. + public static AssociationTypeOption GetAssociationTypeOption(Sax.AssociationType associationType, bool reversed) + { + switch (associationType) + { + case Sax.AssociationType.Affiliate: return reversed ? AssociationTypeOption.AffiliatedTo : AssociationTypeOption.AffiliateParent; + case Sax.AssociationType.Partner: return AssociationTypeOption.Partner; + } + return AssociationTypeOption.Unknown; + } + public static String GetOptionLabel(AssociationTypeOption associationTypeOption) + { + switch (associationTypeOption) + { + case AssociationTypeOption.AffiliateParent: return optionLabel_AffiliatedTo; + case AssociationTypeOption.AffiliatedTo: return optionLabel_Affiliate; + case AssociationTypeOption.Partner: return optionLabel_Partner; + } + return ""; + } + } + + //------------------------------------------------------------------- + // Association data. + //------------------------------------------------------------------- + private class AssociationListData : AjaxResponse_Data.ItemData_Base + { + public class OrganisationData + { + public String Id { get; set; } + public String Name { get; set; } + } + public OrganisationData Organisation { get; } = new OrganisationData(); + public OrganisationData OrganisationAssoc { get; } = new OrganisationData(); + public AssociationTypeData Assoc { get; } = new AssociationTypeData(); + } + private class AssociationItemData : AssociationListData + { + } + private void PopulateAssociationResponseListData(AssociationListData data, SaxItemAssociation itemAssociation, SaxOrganisation organisation, SaxOrganisation organisationAssoc) + { + data.Id = SysId.ToString(itemAssociation.Id); + // Organisation. + data.Organisation.Id = SysId.ToString(organisation.Id); + data.Organisation.Name = organisation.Name; + // Associated Organisation. + data.OrganisationAssoc.Id = SysId.ToString(organisationAssoc.Id); + data.OrganisationAssoc.Name = organisationAssoc.Name; + // Association type. + bool associationReversed = itemAssociation.ItemIdTo.Id.Equals(organisation.Id); + String associationLabel = ""; + if (itemAssociation.AssociationType == Sax.AssociationType.Affiliate) + associationLabel = associationReversed ? "Member organisation" : associationLabel = "Parent organisation"; + else if (itemAssociation.AssociationType == Sax.AssociationType.Partner) + associationLabel = "Partner organisation"; + data.Assoc.Populate(itemAssociation.AssociationType, associationReversed, associationLabel); + // Common properties. + data.StatusCode = itemAssociation.StatusCode; + data.StatusDesc = itemAssociation.StatusDesc; + } + private void PopulateAssociationResponseItemData(AssociationItemData data, SaxItemAssociation itemAssociation, SaxOrganisation organisation, SaxOrganisation organisationAssoc) + { + PopulateAssociationResponseListData(data, itemAssociation, organisation, organisationAssoc); + } + + //------------------------------------------------------------------- + // Get Organisation Association List ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_AssociationList : AjaxResponse_Data + { + // Construction. + public AjaxResponse_AssociationList(SaxModel_Admin model) : base(model) { } + // Association list. + public List Associations { get; } = new List(); + // Reference data. + public List AssociationTypes { get; } = new List(); + public List Statuses { get; } = new List(); + public String DefaultStatusCode { get; set; } + } + //------------------------------------------------------------------- + [HttpPost] + [Route("Organisation/Ajax/GetAssociationList")] + [Route("Organisation/Ajax/GetAssociations")] + public IActionResult Ajax_GetAssociationList(Model_OrganisationAssociations model) + { + String fn = GetType().Name + ".Ajax_GetAssociationList"; + String messageTitle = Localiser["caption.organisation.associations"]; + AjaxResponse_AssociationList responseData = new AjaxResponse_AssociationList(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Organisation Id is mandatory. + SysId organisationId = model.Filter.OrganisationId.ToSysId(); + if (!SysId.IsValid(organisationId)) + { + SaLogger.Warn(fn + " Request to retrieve associations without valid organisation Id."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"])); + } + + // Reference data - association types. + // 'Label' is option caption to add new association of the specified type. + responseData.AssociationTypes.Add(new AssociationTypeData(AssociationTypeOption.AffiliateParent)); + responseData.AssociationTypes.Add(new AssociationTypeData(AssociationTypeOption.AffiliatedTo)); + responseData.AssociationTypes.Add(new AssociationTypeData(AssociationTypeOption.Partner)); + + // Reference data - statuses. + foreach (SaStatus status in SaxItemAssociation.ValidStatuses.FindAll(item => item != SaStatus.Deleted)) + responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status)); + responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SaxItemAssociation.DefaultStatus); + + // Get organisation associations. + GetOrganisationAssociations(model, organisationId, responseData.Associations); + + if (model.Paging.IsPaged) + model.Paging.ItemCount = (ushort)responseData.Associations.Count; + + // Complete response. + responseData.SetPaging(model); + responseData.Success = true; + return Json(responseData); + } + private void GetOrganisationAssociations(SaxModel_Admin model, SysId organisationId, List associations) + { + String fn = GetType().Name + ".GetOrganisationAssociations"; + + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposableItems = new DisposableCollection()) + { + + // Item filter. + SaxItemAssociation.Params prmItemAssociation = new SaxItemAssociation.Params(); + prmItemAssociation.ItemIdsIncluded.Add(new ItemId((short)Sax.DataItemType.Organisation, organisationId)); + prmItemAssociation.StatusCat = SaxItemAssociation.StatusCat.NotDeleted; + model.Paging.ItemTotal = (ulong)ItemDataMgr.GetItemAssociationCount(prmItemAssociation); + model.PopulatePagingTo(prmItemAssociation.ResultsPaging); + + // Item columns. + ColumnDfn colId = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.Id); + ColumnDfn colItemTypeFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeFrom); + ColumnDfn colItemIdFrom = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdFrom); + ColumnDfn colItemTypeTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemTypeTo); + ColumnDfn colItemIdTo = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.ItemIdTo); + ColumnDfn colAssociationType = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.AssociationType); + ColumnDfn colStatus = ItemDataMgr.GetItemAssociationColumnDfn(SaxItemAssociation.Column.Status); + List columns = new List() + { + colId, + colItemTypeFrom, colItemIdFrom, + colItemTypeTo, colItemIdTo, + colAssociationType, + colStatus + }; + + // Query items. + List organisationIds = new List(); + using (DbResultSet resultSet = ItemDataMgr.ExecuteItemAssociationQuery(columns, prmItemAssociation)) + { + while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) + { + NamedValue.Map values = resultSet.GetRecordValues(); + AssociationListData associationData = new AssociationListData() + { + Id = values.GetString(colId.DataName), + StatusCode = values.GetString(colStatus.DataName), + StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName)), + }; + // Items. + bool assiationReversed = false; + ItemId itemIdFrom = new ItemId((short)values.GetLong(colItemTypeFrom.DataName), new SysId(values.GetLong(colItemIdFrom.DataName))); + ItemId itemIdTo = new ItemId((short)values.GetLong(colItemTypeTo.DataName), new SysId(values.GetLong(colItemIdTo.DataName))); + if (ItemId.IsValid(itemIdFrom) && ItemId.IsValid(itemIdTo) && itemIdFrom.Type == (int)Sax.DataItemType.Organisation && itemIdTo.Type == (int)Sax.DataItemType.Organisation) + { + organisationIds.AddId(itemIdFrom.Id); + organisationIds.AddId(itemIdTo.Id); + if (itemIdFrom.Id.Equals(organisationId)) + { + associationData.Organisation.Id = SysId.ToString(itemIdFrom.Id); + associationData.OrganisationAssoc.Id = SysId.ToString(itemIdTo.Id); + } + else if (itemIdTo.Id.Equals(organisationId)) + { + assiationReversed = true; + associationData.Organisation.Id = SysId.ToString(itemIdTo.Id); + associationData.OrganisationAssoc.Id = SysId.ToString(itemIdFrom.Id); + } + else if (SacsSystem.DebugMode) + // Track invalid associations, ie. where neither item is this organisation. + Debugger.Break(); + } + else if (SacsSystem.DebugMode) + // Track invalid associations, ie. where either item is not an organisation. + Debugger.Break(); + // Association type. + Sax.AssociationType associationType = (Sax.AssociationType)values.GetLong(colAssociationType.DataName); + associationData.Assoc.Populate(associationType, assiationReversed); + // Add association to the list. + associations.Add(associationData); + } + } + // Populate organisation details. + SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params(); + prmOrganisation.IdsIncluded.AddRange(organisationIds); + prmOrganisation.StatusCat = SaxOrganisation.StatusCat.Any; + List organisations = AccountMgr.GetOrganisationList(prmOrganisation); + disposableItems.AddRange(organisations); + foreach (AssociationListData associationData in associations) + { + associationData.Organisation.Name = organisations.GetOrganisationName(new SysId(StringUtil.ToLong(associationData.Organisation.Id))); + associationData.OrganisationAssoc.Name = organisations.GetOrganisationName(new SysId(StringUtil.ToLong(associationData.OrganisationAssoc.Id))); + } + } + } + + //------------------------------------------------------------------- + // Get Organisation Association ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_Association : AjaxResponse_Data + { + // Construction. + public AjaxResponse_Association(SaxModel_Admin model) : base(model) { } + // Association details. + public AssociationItemData Association { get; } = new AssociationItemData(); + } + //------------------------------------------------------------------- + [HttpPost] + [Route("Organisation/Ajax/GetAssociation")] + public IActionResult Ajax_GetAssociation(Model_OrganisationAssociations model) + { + String fn = GetType().Name + ".Ajax_GetAssociation"; + String messageTitle = Localiser["caption.organisation.association"]; + AjaxResponse_Association responseData = new AjaxResponse_Association(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposableItems = new DisposableCollection()) + { + + // Identify item. + SysId itemAssociationId = model.ItemAssociationId.ToSysId(); + if (!SysId.IsValid(itemAssociationId)) + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"])); + + // Retrieve association. + SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId); + disposableItems.Add(itemAssociation); + if (itemAssociation == null) + { + SaLogger.Warn(fn + " Failed to retrieve Item Association for Id: '" + model.ItemAssociationId + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); + } + + // Identify organisations. + SysId organisationId = model.OrganisationId.ToSysId(); + SysId organisationIdAssoc = null; + if (!SysId.IsValid(organisationId)) + { + SaLogger.Warn(fn + " Organisation Id must be supplied."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.incomplete"])); + } + + // Validate the association. + if (itemAssociation.ItemIdFrom.Type != (int)Sax.DataItemType.Organisation) + { + SaLogger.Warn(fn + " Inconsistent association 'From' item type: " + AssociationTypeCodes.GetCodeForType(itemAssociation.ItemIdFrom.Type) + ". Expected: Organisation."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + if (itemAssociation.ItemIdTo.Type != (int)Sax.DataItemType.Organisation) + { + SaLogger.Warn(fn + " Inconsistent association 'To' item type: " + AssociationTypeCodes.GetCodeForType(itemAssociation.ItemIdTo.Type) + ". Expected: Organisation."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Identify organisations from association items. + // The specified organisation must be one or other of the association's items. + if (itemAssociation.ItemIdFrom.Id.Equals(organisationId)) + organisationIdAssoc = itemAssociation.ItemIdTo.Id; + else if (itemAssociation.ItemIdTo.Id.Equals(organisationId)) + organisationIdAssoc = itemAssociation.ItemIdFrom.Id; + else + { + SaLogger.Warn(fn + " Inconsistent association - Specified organisation is neither item."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Retrieve Organisation. + SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId); + disposableItems.Add(organisation); + if (organisation == null) + { + SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: '" + organisationId + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); + } + + // Retrieve associated Organisation. + SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc); + disposableItems.Add(organisationAssoc); + if (organisationAssoc == null) + { + SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: '" + organisationIdAssoc + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); + } + + // Construct response. + PopulateAssociationResponseItemData(responseData.Association, itemAssociation, organisation, organisationAssoc); + } + + responseData.Success = true; + return Json(responseData); + } + + //------------------------------------------------------------------- + // Store Organisation Association ajax request. + //------------------------------------------------------------------- + [HttpPost] + [Route("Organisation/Ajax/StoreAssociation")] + public IActionResult Ajax_StoreAssociation(Model_OrganisationAssociations model) + { + String fn = GetType().Name + ".Ajax_StoreAssociation"; + String messageTitle = Localiser["caption.organisation.association"]; + AjaxResponse_Association responseData = new AjaxResponse_Association(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Validate item properties. + model.ValidateOrganisationAssociationData(responseData); + if (responseData.HasControlErrors()) + return Json(responseData); + + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposableItems = new DisposableCollection()) + { + + // Organisation. + SysId organisationId = model.OrganisationId.ToSysId(); + SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId); + disposableItems.Add(organisation); + if (organisation == null) + { + SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: " + model.OrganisationId); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.incomplete"])); + } + + // Associated Organisation. + SysId organisationIdAssoc = model.OrganisationIdAssoc.ToSysId(); + SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc); + disposableItems.Add(organisationAssoc); + if (organisationAssoc == null) + { + SaLogger.Warn(fn + " Failed to retrieve associated Organisation for Id: " + model.OrganisationIdAssoc); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.incomplete"])); + } + if (organisationIdAssoc.Equals(organisationId)) + { + SaLogger.Warn(fn + " Associated organisation must not be the same as the organisation."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Association type. + Sax.AssociationType associationType = model.GetAssociationTypeForOption(model.Association.GetAssociationTypeOption()); + if ((int)associationType < 1) + { + SaLogger.Warn(fn + " Association Type must be specified."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + AssociationTypeOption associationTypeOption = model.Association.GetAssociationTypeOption(); + if ((int)associationTypeOption < 1) + { + SaLogger.Warn(fn + " Association Type Option must be specified."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + if (!model.IsConsistentWith(associationTypeOption, associationType)) + { + SaLogger.Warn(fn + " Association Type Option (" + associationTypeOption + ") is inconsistent with Association Type (" + associationType + ")."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Identify From/To items. + ItemId itemIdFrom = organisation.GetItemId(); + ItemId itemIdTo = organisationAssoc.GetItemId(); + if (model.IsAssociationTypeDirectionReversed(associationTypeOption)) + { + itemIdFrom = organisationAssoc.GetItemId(); + itemIdTo = organisation.GetItemId(); + } + + // Retrieve existing association. + SysId itemAssociationId = model.ItemAssociationId.ToSysId(); + if (SysId.IsValid(itemAssociationId) == StringUtil.ToBool(model.NewItem)) + { + // Inconsistentcy between the 'Existing' flag and whether the Item Association Id has been specified. + SaLogger.Warn(fn + " Item Association Id " + (StringUtil.ToBool(model.NewItem) ? "specified for new item" : "not specified for existing item") + "."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId); + disposableItems.Add(itemAssociation); + if (itemAssociation == null && SysId.IsValid(itemAssociationId)) + { + SaLogger.Warn(fn + " Failed to retrieve item association for Id: '" + itemAssociationId + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); + } + + if (itemAssociation != null) + { + // Validate From/To items. + if (!itemAssociation.ItemIdFrom.Equals(itemIdFrom)) + { + SaLogger.Warn(fn + " Inconsistent association - expected 'From' Item Id: " + SysId.ToString(organisation.Id) + ". Found: " + SysId.ToString(itemAssociation.ItemIdFrom.Id)); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); + } + if (!itemAssociation.ItemIdTo.Equals(itemIdTo)) + { + SaLogger.Warn(fn + " Inconsistent association - expected 'To' Item Id: " + SysId.ToString(organisation.Id) + ". Found: " + SysId.ToString(itemAssociation.ItemIdTo.Id)); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"])); + } + } + else + { + // Item Association not identified. + + // Check for deleted association that can be reused. + SaxItemAssociation.Params itemAssociationParams = new SaxItemAssociation.Params(); + + if (itemAssociation != null) + itemAssociation.Status = SaxItemAssociation.DefaultStatus; + else + { + // Association not found - create a new one. + itemAssociation = ItemDataMgr.CreateItemAssociation(itemIdFrom, itemIdTo, associationType); + } + disposableItems.Add(itemAssociation); + } + + // Populate item properties. + if (model.Association.StatusCode != null) + itemAssociation.Status = model.Association.GetStatus(); + + // Store item. + if (!SysId.IsValid(itemAssociation.Id)) + { + if (!ItemDataMgr.InsertItemAssociation(itemAssociation, DbUpdateInfo)) + { + SaLogger.Warn(fn + " Failed to insert user organisation: " + ItemDataMgr.ErrorStateMessage); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage)); + } + } + else + { + if (!ItemDataMgr.UpdateItemAssociation(itemAssociation, DbUpdateInfo)) + { + SaLogger.Warn(fn + " Failed to update user organisation [Id:" + SysId.ToString(itemAssociation.Id) + "]: " + ItemDataMgr.ErrorStateMessage); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage)); + } + } + + // Construct response. + PopulateAssociationResponseItemData(responseData.Association, itemAssociation, organisation, organisationAssoc); + } + + responseData.Success = true; + return Json(responseData); + } + + //------------------------------------------------------------------- + // Remove Organisation Association ajax request. + //------------------------------------------------------------------- + [HttpPost] + [Route("Organisation/Ajax/RemoveAssociation")] + public IActionResult Ajax_RemoveAssociation(Model_OrganisationAssociations model) + { + String fn = GetType().Name + ".Ajax_RemoveAssociation"; + String messageTitle = Localiser["caption.organisation.association"]; + AjaxResponse_Association responseData = new AjaxResponse_Association(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposableItems = new DisposableCollection()) + { + + // Organisation. + SysId organisationId = model.OrganisationId.ToSysId(); + SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId); + disposableItems.Add(organisation); + if (organisation == null) + { + SaLogger.Warn(fn + " Failed to retrieve Organisation for Id: '" + model.OrganisationId + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.incomplete"])); + } + + // Association Organisation. + SysId organisationIdAssoc = model.OrganisationIdAssoc.ToSysId(); + SaxOrganisation organisationAssoc = AccountMgr.GetOrganisationById(organisationIdAssoc); + disposableItems.Add(organisationAssoc); + if (organisationAssoc == null) + { + SaLogger.Warn(fn + " Failed to retrieve associated Organisation for Id: '" + model.OrganisationIdAssoc + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.incomplete"])); + } + if (organisationIdAssoc.Equals(organisationId)) + { + SaLogger.Warn(fn + " Associated organisation must not be the same as the organisation."); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Item Association. + SysId itemAssociationId = model.ItemAssociationId.ToSysId(); + SaxItemAssociation itemAssociation = ItemDataMgr.GetItemAssociationById(itemAssociationId); + disposableItems.Add(itemAssociation); + if (itemAssociation == null) + { + SaLogger.Warn(fn + " Failed to retrieve Item Association for Id: '" + itemAssociationId + "'"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"])); + } + + // Validate association Item Ids. + if (!itemAssociation.ItemIdFrom.Id.Equals(organisation.Id) && !itemAssociation.ItemIdTo.Id.Equals(organisation.Id)) + { + SaLogger.Warn(fn + " Inconsistent user organisation properties. Organisation must be 'From' or 'To' item"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + if (!itemAssociation.ItemIdFrom.Id.Equals(organisationAssoc.Id) && !itemAssociation.ItemIdTo.Id.Equals(organisationAssoc.Id)) + { + SaLogger.Warn(fn + " Inconsistent user organisation properties. Associated Organisation must be 'From' or 'To' item"); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.data.inconsistent"])); + } + + // Logically delete item. + itemAssociation.Status = SaStatus.Deleted; + if (!ItemDataMgr.UpdateItemAssociation(itemAssociation, DbUpdateInfo)) + { + SaLogger.Warn(fn + " Failed to update Item Association [Id:" + SysId.ToString(itemAssociation.Id) + "]: " + ItemDataMgr.ErrorStateMessage); + return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ItemDataMgr.ErrorStateMessage)); + } + + // Construct response. + PopulateAssociationResponseItemData(responseData.Association, itemAssociation, organisation, organisationAssoc); + } + + responseData.Success = true; + return Json(responseData); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Members-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Members.cs similarity index 93% rename from SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Members-Ajax.cs rename to SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Members.cs index 8207e4d..f0b0e6a 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Members-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax-Members.cs @@ -15,13 +15,13 @@ using System.Threading.Tasks; namespace Saxonite.Net.Core.Web.Admin.Controllers { //======================================================================= - // Controller: Organisation - Members - Ajax + // Controller: Organisation - Ajax - Members //======================================================================= partial class OrganisationController { //------------------------------------------------------------------- // Member data. - private class MemberData_List : AjaxResponse_Data.ItemData_Base + private class MemberListData : AjaxResponse_Data.ItemData_Base { // User. public String UserAccountId { get; set; } @@ -38,12 +38,12 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public int RoleCount { get; set; } public bool? Member { get; set; } = null; } - private class MemberData_Full : MemberData_List + private class MemberItemData : MemberListData { // Organisation user. public List RoleCodes { get; } = new List(); } - private void PopulateMemberResponseData(MemberData_List data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation) + private void PopulateMemberResponseListData(MemberListData data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation) { data.Id = SysId.ToString(userOrganisation.Id); // User. @@ -63,9 +63,9 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers if (userOrganisation.GetOrganisationRoles().ToList().Exists(item => item == Sax.OrganisationRole.Member)) data.Member = true; } - private void PopulateMemberResponseData(MemberData_Full data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation) + private void PopulateMemberResponseItemData(MemberItemData data, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation) { - PopulateMemberResponseData(data as MemberData_List, userOrganisation, userAccount, organisation); + PopulateMemberResponseListData(data, userOrganisation, userAccount, organisation); // Organisation user: // Exclude 'Member' role. foreach (Sax.OrganisationRole organisationRole in userOrganisation.GetOrganisationRoles().ToList().FindAll(item => item != Sax.OrganisationRole.Member)) @@ -80,7 +80,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_MemberList(SaxModel_Admin model) : base(model) { } // Member list. - public List Members { get; } = new List(); + public List Members { get; } = new List(); // Reference data. public List MemberRoles { get; } = new List(); public List Statuses { get; } = new List(); @@ -92,7 +92,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetMemberList(Model_OrganisationMembers model) { String fn = GetType().Name + ".Ajax_GetMemberList"; - String messageTitle = Localiser["organisation.caption.members"]; + String messageTitle = Localiser["caption.organisation.members"]; AjaxResponse_MemberList responseData = new AjaxResponse_MemberList(model); // Validate session. @@ -128,7 +128,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers responseData.Success = true; return Json(responseData); } - private void GetOrganisationMembers(SaxModel_Admin model, SysId organisationId, List members) + private void GetOrganisationMembers(SaxModel_Admin model, SysId organisationId, List members) { // Item filter. SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params(); @@ -165,7 +165,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); - MemberData_List memberData = new MemberData_List() + MemberListData memberData = new MemberListData() { Id = values.GetString(colId.DataName), // User. @@ -196,7 +196,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_Member(SaxModel_Admin model) : base(model) { } // Member details. - public MemberData_Full Member { get; } = new MemberData_Full(); + public MemberItemData Member { get; } = new MemberItemData(); } //------------------------------------------------------------------- [HttpPost] @@ -204,7 +204,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetMember(Model_OrganisationMembers model) { String fn = GetType().Name + ".Ajax_GetItem"; - String messageTitle = Localiser["organisation.caption.member"]; + String messageTitle = Localiser["caption.organisation.member"]; AjaxResponse_Member responseData = new AjaxResponse_Member(model); // Validate session. @@ -248,7 +248,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers } // Construct response. - PopulateMemberResponseData(responseData.Member, userOrganisation, userAccount, organisation); + PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation); } responseData.Success = true; @@ -263,7 +263,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_StoreMember(Model_OrganisationMembers model) { String fn = GetType().Name + ".Ajax_StoreMember"; - String messageTitle = Localiser["organisation.caption.member"]; + String messageTitle = Localiser["caption.organisation.member"]; AjaxResponse_Member responseData = new AjaxResponse_Member(model); // Validate session. @@ -375,7 +375,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers } // Construct response. - PopulateMemberResponseData(responseData.Member, userOrganisation, userAccount, organisation); + PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation); } responseData.Success = true; @@ -390,7 +390,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_RemoveMember(Model_OrganisationMembers model) { String fn = GetType().Name + ".Ajax_RemoveMember"; - String messageTitle = Localiser["organisation.caption.member"]; + String messageTitle = Localiser["caption.organisation.member"]; AjaxResponse_Member responseData = new AjaxResponse_Member(model); // Validate session. @@ -457,7 +457,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers } // Construct response. - PopulateMemberResponseData(responseData.Member, userOrganisation, userAccount, organisation); + PopulateMemberResponseItemData(responseData.Member, userOrganisation, userAccount, organisation); } responseData.Success = true; diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs index 017f8bf..126d012 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Ajax.cs @@ -133,7 +133,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetList(Model_Organisation model) { String fn = GetType().Name + ".Ajax_GetList"; - String messageTitle = Localiser["organisation.caption.organisations"]; + String messageTitle = Localiser["caption.organisations"]; AjaxResponse_OrganisationList responseData = new AjaxResponse_OrganisationList(model); // Validate session. @@ -253,7 +253,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetItem(Model_Organisation model) { String fn = GetType().Name + ".Ajax_GetItem"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model); // Validate session. @@ -299,7 +299,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_StoreItem(Model_Organisation model) { String fn = GetType().Name + ".Ajax_StoreItem"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_Organisation responseData = new AjaxResponse_Organisation(model); // Validate session. diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs index ab606ae..b80ccde 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController-Images-Ajax.cs @@ -51,7 +51,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_GetImages(Model_Organisation model) { String fn = GetType().Name + ".Ajax_GetImages"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_OrganisationImages responseData = new AjaxResponse_OrganisationImages(model); // Validate session. @@ -113,7 +113,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers { String fn = GetType().Name + ".UploadOrganisationLogoImage"; AjaxResponse_UploadOrganisationLogoImage responseData = new AjaxResponse_UploadOrganisationLogoImage(model); - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; // Validate session and referrer. if (!ValidReferer) return Forbid(); @@ -223,7 +223,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public IActionResult Ajax_StoreImages(Model_Organisation model) { String fn = GetType().Name + ".Ajax_StoreImages"; - String messageTitle = Localiser["organisation.caption.organisation"]; + String messageTitle = Localiser["caption.organisation"]; AjaxResponse_OrganisationImages responseData = new AjaxResponse_OrganisationImages(model); // Validate session. diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController.cs index cd392bb..e281398 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/OrganisationController.cs @@ -68,10 +68,37 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers return RedirectToAction("", ""); // Retrieve organisation. - SaxOrganisation organisation = AccountMgr.GetOrganisationById(model.Filter.OrganisationId.ToSysId()); + SaxOrganisation organisation = AccountMgr.GetOrganisationById(model.OrganisationId.ToSysId()); if (organisation == null) RedirectToAction("", "Organisation"); - model.MemberOrganisationName = organisation?.Name; + model.Filter.OrganisationId= SysId.ToString(organisation.Id); + model.Filter.OrganisationName = organisation.Name; + + // Paging. + model.Paging.PageNo = 1; + model.Paging.PageLength = 12; + + return View(model); + } + + //------------------------------------------------------------------- + /// + /// Organisation Associations action. + /// - POST action to allow Organisation Id to be supplied, eg. from Organsiations page. + /// + [HttpPost] + public IActionResult Associations(Model_OrganisationAssociations model) + { + // Validate session. + if (!ValidUserSession) + return RedirectToAction("", ""); + + // Retrieve organisation. + SaxOrganisation organisation = AccountMgr.GetOrganisationById(model.OrganisationId.ToSysId()); + if (organisation == null) + RedirectToAction("", "Organisation"); + model.Filter.OrganisationId = SysId.ToString(organisation.Id); + model.Filter.OrganisationName = organisation.Name; // Paging. model.Paging.PageNo = 1; diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/SaxController_Admin.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/SaxController_Admin.cs index 5a0ba02..83482b3 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/SaxController_Admin.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/SaxController_Admin.cs @@ -143,16 +143,16 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers { String keepLoggedInCookieValue = GenerateKeepLoggedInCookieValue(); int cookieExpiresDays = Math.Max(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Min, Math.Min(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Max, AppConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays)); - SetResponseCookie(CookieName_KeepLoggedIn, keepLoggedInCookieValue, DateTime.Now.AddDays(cookieExpiresDays), true); + SetResponseCookie(KeepLoggedIn.CookieName, keepLoggedInCookieValue, DateTime.Now.AddDays(cookieExpiresDays), true); SaLogger.Info(this.GetType().Name + ".SetKeepLoggedInCookie 'Keep Logged In' cookie set. Value: " + keepLoggedInCookieValue); } /// Set the 'Keep Logged In' response cookie to expired with no data. public void ClearKeepLoggedInCookie() { - if (StringUtil.IsEmpty(GetRequestCookie(CookieName_KeepLoggedIn))) return; + if (StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName))) return; // Clear cookie by setting expiry date in the past. - SetResponseCookie(CookieName_KeepLoggedIn, "", DateTime.Today.AddDays(-7), true); + SetResponseCookie(KeepLoggedIn.CookieName, "", DateTime.Today.AddDays(-7), true); SaLogger.Info(GetType().Name + ".ClearKeepLoggedInCookie 'Keep Logged In' cookie cleared."); } @@ -162,11 +162,13 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // to ensure that cookie value can be decrypted even if application restarts in the meantime. // - Generating IV from same key results in different value each time. // - IV Must be regenerated if key is changed: uncomment 'Generated' variable and copy resulting value to IV variable. - // NB - public static String CookieName_KeepLoggedIn = "SXKLI"; - public static String Base64Key_KeepLoggedIn = SacsEncryptionHelper.EncodePlainKey("<=Saxonite^{kEEp+1Ogg3d-IN}~32*>", SacsEncryptionHelper.KeyLength); - public static String Base64IV_KeepLoggedIn_Generated = SacsEncryptionHelper.InitSymmetricEncryptionIV(Base64Key_KeepLoggedIn); - public static String Base64IV_KeepLoggedIn = "YOX10FIPp1zM1pg5U6fW7A=="; + public static class KeepLoggedIn + { + public static String CookieName = "SXKLI"; + public static String Base64Key = SacsEncryptionHelper.EncodePlainKey("<=Saxonite^{kEEp+1Ogg3d-IN}~32*>", SacsEncryptionHelper.KeyLength); + public static String Base64IV = "YOX10FIPp1zM1pg5U6fW7A=="; + private static String Base64IV_Generated = SacsEncryptionHelper.InitSymmetricEncryptionIV(KeepLoggedIn.Base64Key); + } //------------------------------------------------------------------- // Keep-logged-in cookie value. @@ -175,7 +177,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers { NameValueCollection keepLoggedInParams = new NameValueCollection(); keepLoggedInParams.Add(ParamName_KeepLoggedIn_UserAccountId, SysId.ToString(SessionData_Admin.User.UserAccountId)); - return EncryptParameters(keepLoggedInParams, Base64IV_KeepLoggedIn, Base64Key_KeepLoggedIn); + return EncryptParameters(keepLoggedInParams, KeepLoggedIn.Base64IV, KeepLoggedIn.Base64Key); } //------------------------------------------------------------------- @@ -196,7 +198,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers KeepLoggedInParams keepLoggedInParams = new KeepLoggedInParams(); if (!StringUtil.IsEmpty(encryptedParams)) { - NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_KeepLoggedIn, Base64Key_KeepLoggedIn); + NameValueCollection linkParams = DecryptParameters(encryptedParams, KeepLoggedIn.Base64IV, KeepLoggedIn.Base64Key); keepLoggedInParams.UserAccountId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_KeepLoggedIn_UserAccountId))); } if (DebugMode) SaLogger.Info(GetType().Name + ".ExtractKeepLoggedInParams UserAccountId: " + SysId.ToString(keepLoggedInParams.UserAccountId)); diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs index f3c261f..f289fae 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/SecurityController-Ajax.cs @@ -90,7 +90,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers return Json(responseData); // Resend the cookie to extend the expiry date if it is currently populated. - if (!StringUtil.IsEmpty(GetRequestCookie(CookieName_KeepLoggedIn))) + if (!StringUtil.IsEmpty(GetRequestCookie(KeepLoggedIn.CookieName))) SetKeepLoggedInCookie(); // Construct response. diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs index eba7668..065fc82 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/UserController-Ajax.cs @@ -19,7 +19,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers { //------------------------------------------------------------------- // User data. - private class UserData_List : AjaxResponse_Data.ItemData_Base + private class UserListData : AjaxResponse_Data.ItemData_Base { public String EmailAddress { get; set; } public String DisplayName { get; set; } @@ -34,7 +34,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public String LastOnlineLoginAt { get; set; } public String LastAdminLoginAt { get; set; } } - private class UserData_Full : UserData_List + private class UserItemData : UserListData { public String RegionIdCountry { get; set; } public String RegionIdProvince { get; set; } @@ -48,7 +48,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // User roles. public List userRoleCodes { get; } = new List(); } - private void PopulateUserResponseData(SaxModel_Admin model, UserData_List data, SaxUserAccount user, List userSports, List userRoles) + private void PopulateUserResponseListData(SaxModel_Admin model, UserListData data, SaxUserAccount user, List userSports, List userRoles) { data.Id = SysId.ToString(user.Id); data.EmailAddress = user.EmailAddress; @@ -71,9 +71,9 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers if (userRole_SystemAdmin != null) data.LastAdminLoginAt = model.FormatDateTimeForDisplay(userRole_SystemAdmin.LastLoginAt); } - private void PopulateUserResponseData(SaxModel_Admin model, UserData_Full data, SaxUserAccount user, List userSports, List userRoles) + private void PopulateUserResponseItemData(SaxModel_Admin model, UserItemData data, SaxUserAccount user, List userSports, List userRoles) { - PopulateUserResponseData(model, data as UserData_List, user, userSports, userRoles); + PopulateUserResponseListData(model, data, user, userSports, userRoles); data.RegionIdCountry = SysId.ToString(user.RegionIdCountry); data.RegionIdProvince = SysId.ToString(user.RegionIdProvince); @@ -81,12 +81,12 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // User sports. if (userSports != null && !userSports.IsEmpty()) { - data.Sports = new List(); + data.Sports = new List(); List sports = ReferenceMgr.GetSportListByIds(userSports.GetSportIds()); foreach (SaxUserSport userSport in userSports) { SaxSport sport = sports.GetSportById(userSport.SportId); - UserData_Full.UserSportData userSportData = new UserData_Full.UserSportData() + UserItemData.UserSportData userSportData = new UserItemData.UserSportData() { SportId = SysId.ToString(userSport.SportId), SportName = sport?.Name ?? null @@ -130,7 +130,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_UserList(SaxModel_Admin model) : base(model) { } // User list. - public List Users { get; } = new List(); + public List Users { get; } = new List(); // Reference data. public List UserRoles { get; } = new List(); public List Statuses { get; } = new List(); @@ -205,7 +205,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); - UserData_List userData = new UserData_List() + UserListData userData = new UserListData() { Id = values.GetString(colId.DataName), EmailAddress = values.GetString(colEmail.DataName), @@ -246,7 +246,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_User(SaxModel_Admin model) : base(model) { } // User details. - public UserData_Full user { get; } = new UserData_Full(); + public UserItemData user { get; } = new UserItemData(); } //------------------------------------------------------------------- [HttpPost] @@ -290,7 +290,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers disposableItems.AddRange(userRoles); // Construct response. - PopulateUserResponseData(model, responseData.user, user, userSports, userRoles); + PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles); responseData.Success = true; } return Json(responseData); @@ -342,7 +342,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers disposableItems.AddRange(userRoles); // Construct response. - PopulateUserResponseData(model, responseData.user, user, userSports, userRoles); + PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles); responseData.Success = true; } return Json(responseData); @@ -478,7 +478,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers disposableItems.AddRange(userSports); // Construct response. - PopulateUserResponseData(model, responseData.user, user, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active)); + PopulateUserResponseItemData(model, responseData.user, user, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active)); responseData.Success = true; } return Json(responseData); @@ -554,7 +554,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers disposableItems.AddRange(userSports); // Construct response. - PopulateUserResponseData(model, responseData.user, userAccount, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active)); + PopulateUserResponseItemData(model, responseData.user, userAccount, userSports, userRoles.GetUserRolesByStatus(SaStatus.Active)); responseData.SetNotification(messageTitle, "Emails sent: " + emailsSentCount); responseData.Success = true; } diff --git a/SaxoniteCoreWebAdmin/Admin/Controllers/UsersOnlineController-Ajax.cs b/SaxoniteCoreWebAdmin/Admin/Controllers/UsersOnlineController-Ajax.cs index 98848e2..a072ec9 100644 --- a/SaxoniteCoreWebAdmin/Admin/Controllers/UsersOnlineController-Ajax.cs +++ b/SaxoniteCoreWebAdmin/Admin/Controllers/UsersOnlineController-Ajax.cs @@ -19,7 +19,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers { //------------------------------------------------------------------- // User data. - private class UserData_List : AjaxResponse_Data.ItemData_Base + private class UserListData : AjaxResponse_Data.ItemData_Base { public String EmailAddress { get; set; } public String DisplayName { get; set; } @@ -29,10 +29,10 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers public String LastLoginAt { get; set; } public String OnlineAt { get; set; } } - private class UserData_Full : UserData_List + private class UserItemData : UserListData { } - private void PopulateUserResponseData(SaxModel_Admin model, UserData_List data, SaxUserAccount user, SaxUserOnline userOnline) + private void PopulateUserResponseListData(SaxModel_Admin model, UserListData data, SaxUserAccount user, SaxUserOnline userOnline) { data.Id = SysId.ToString(user.Id); data.EmailAddress = user.EmailAddress; @@ -44,9 +44,9 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers if (userOnline != null) data.OnlineAt = model.FormatDateTimeForDisplay(userOnline.OnlineAt); } - private void PopulateUserResponseData(SaxModel_Admin model, UserData_Full data, SaxUserAccount user, SaxUserOnline userOnline) + private void PopulateUserResponseItemData(SaxModel_Admin model, UserItemData data, SaxUserAccount user, SaxUserOnline userOnline) { - PopulateUserResponseData(model, data as UserData_List, user, userOnline); + PopulateUserResponseListData(model, data, user, userOnline); } //------------------------------------------------------------------- @@ -60,7 +60,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_UserList(SaxModel_Admin model) : base(model) { } // User list. - public List Users { get; } = new List(); + public List Users { get; } = new List(); } //------------------------------------------------------------------- [HttpPost] @@ -107,7 +107,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers while (resultSet != null && resultSet.HasRows && resultSet.NextRecord()) { NamedValue.Map values = resultSet.GetRecordValues(); - UserData_List userData = new UserData_List() + UserListData userData = new UserListData() { Id = values.GetString(colUserAccountId.DataName), EmailAddress = values.GetString(colEmail.DataName), @@ -138,7 +138,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers // Construction. public AjaxResponse_User(SaxModel_Admin model) : base(model) { } // User details. - public UserData_Full user { get; } = new UserData_Full(); + public UserItemData user { get; } = new UserItemData(); } //------------------------------------------------------------------- [HttpPost] @@ -178,7 +178,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers disposableItems.Add(userOnline); // Construct response. - PopulateUserResponseData(model, responseData.user, user, userOnline); + PopulateUserResponseItemData(model, responseData.user, user, userOnline); responseData.Success = true; } return Json(responseData); diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationAssociations.cs b/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationAssociations.cs new file mode 100644 index 0000000..9a05f9f --- /dev/null +++ b/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationAssociations.cs @@ -0,0 +1,156 @@ +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.Base.App; +using Saxonite.Net.Core.Web.Base.App; +using Saxonite.Net.Core.Web.Base.Controllers; +using Saxonite.Net.Core.Web.Base.Models; +using Saxonite.Net.Standard.Base.App; +using Saxonite.Net.Standard.Base.Bus; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Threading.Tasks; + +namespace Saxonite.Net.Core.Web.Admin.Models +{ + //======================================================================= + public class Model_OrganisationAssociations : SaxModel_Admin + { + //------------------------------------------------------------------- + // Definitions. + public enum AssociationTypeOption + { + Unknown = 0, + AffiliateParent, + AffiliatedTo, + Partner, + } + + //------------------------------------------------------------------- + // Construction. + public Model_OrganisationAssociations(SaxLocaliser localiser) : + base(localiser) + { + AdditionalFiles_JS.Add("js/sax-org-ass.js"); + } + + //------------------------------------------------------------------- + // List configuration. + public class FilterData + { + public String OrganisationId { get; set; } + public String OrganisationName { get; set; } + } + public FilterData Filter { get; } = new FilterData(); + + //------------------------------------------------------------------- + // Item association. + public String ItemAssociationId { get; set; } + /// Flag to indicate that a new association needs to be created - must be consistent with validity of Item Association Id. + public String NewItem { get; set; } + // Organisation. + public String OrganisationId { get; set; } + // Associated organisation. + public String OrganisationIdAssoc { get; set; } + public class AssociationData + { + // Association type option. + public String TypeOption { get; set; } + public AssociationTypeOption GetAssociationTypeOption() { return EnumUtil.ParseEnum(TypeOption, AssociationTypeOption.Unknown); } + // Association properties. + public String StatusCode { get; set; } + public SaStatus GetStatus() { return SacsSystem.GetStatusForCode(StatusCode); } + } + public AssociationData Association { get; } = new AssociationData(); + + //------------------------------------------------------------------- + // Utilities. + public bool IsAssociationTypeDirectionReversed(AssociationTypeOption associationTypeOption) + { + switch (associationTypeOption) + { + case AssociationTypeOption.AffiliatedTo: + return true; + } + return false; + } + public Sax.AssociationType GetAssociationTypeForOption(AssociationTypeOption associationTypeOption) + { + switch (associationTypeOption) + { + case AssociationTypeOption.AffiliateParent: + case AssociationTypeOption.AffiliatedTo: + return Sax.AssociationType.Affiliate; + case AssociationTypeOption.Partner: + return Sax.AssociationType.Partner; + } + return Sax.AssociationType.Unknown; + } + public bool IsConsistentWith(AssociationTypeOption associationTypeOption, Sax.AssociationType associationType) + { + switch (associationType) + { + case Sax.AssociationType.Affiliate: + return new List() { AssociationTypeOption.AffiliatedTo, AssociationTypeOption.AffiliateParent }.Contains(associationTypeOption); + case Sax.AssociationType.Partner: + return new List() { AssociationTypeOption.Partner }.Contains(associationTypeOption); + } + return false; + } + + //------------------------------------------------------------------- + // Validation. + //------------------------------------------------------------------- + // Organisation association validation. + public bool ValidateOrganisationAssociationData(SaxController_Base.AjaxResponse_Data responseData) + { + + // Associated Organisation. + if (OrganisationIdAssoc != null) + { + // Mandatory. + String controlName = "OrganisationIdAssoc"; + if (!SysId.IsValid(OrganisationIdAssoc.ToSysId())) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + // Must exist. + else if (!AccountMgr.OrganisationExistsById(OrganisationIdAssoc.ToSysId())) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + // Not same as primary organisation. + else if (OrganisationId != null && OrganisationId.ToSysId().Equals(OrganisationIdAssoc.ToSysId())) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + } + + // Association type option. + if (Association.TypeOption != null) + { + // Mandatory. + String controlName = "AssociationTypeOption"; + if (StringUtil.IsEmpty(Association.TypeOption)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + // Valid value. + else if ((int)Association.GetAssociationTypeOption() < 1) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + } + + // Association status. + if (Association.StatusCode != null) + { + // Mandatory. + String controlName = "AssociationStatus"; + if (StringUtil.IsEmpty(Association.StatusCode)) + responseData.SetControlError(controlName, Localiser["msg.validation.mandatory.value"]); + // Valid value. + else if (!SaxOrganisation.ValidStatuses.Contains(Association.GetStatus())) + responseData.SetControlError(controlName, Localiser["msg.validation.invalid.value"]); + } + + return !responseData.HasControlErrors(); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationMembers.cs b/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationMembers.cs index 6f3d369..e32ee8c 100644 --- a/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationMembers.cs +++ b/SaxoniteCoreWebAdmin/Admin/Models/Model_OrganisationMembers.cs @@ -32,18 +32,19 @@ namespace Saxonite.Net.Core.Web.Admin.Models public class FilterData { public String OrganisationId { get; set; } + public String OrganisationName { get; set; } } public FilterData Filter { get; } = new FilterData(); - public String OrganisationId { get { return Filter.OrganisationId; } set { Filter.OrganisationId = value; } } //------------------------------------------------------------------- + // Organisation. + public String OrganisationId { get; set; } // User Organisation (member) properties. public String UserOrganisationId { get; set; } [EmailAddress] public String MemberUserEmailAddress{ get; set; } public String MemberUserAccountId { get; set; } public String MemberOrganisationId { get; set; } - public String MemberOrganisationName { get; set; } public String MemberRoleCodeDelim = ","; public List MemberRoleCodes { get; set; } public List GetMemberRoleCodes() diff --git a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx index c3a1804..fe53973 100644 --- a/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx +++ b/SaxoniteCoreWebAdmin/Localisation/SaxAdminProperties.resx @@ -123,12 +123,39 @@ Image Upload + + Add Member + + + Remove Member + + + Update Member + + + Organisation + Organisation Address + + Organisation Association + + + Organisation Associations + Organisation Images + + Organisation Member + + + Organisation Members + + + Organisations + Sportierre @@ -192,6 +219,15 @@ Assigned + + Associated organisation + + + Association + + + Associations + Available @@ -567,24 +603,6 @@ Organisation to activate: - - Organisation Member - - - Add Member - - - Remove Member - - - Update Member - - - Organisation Members - - - Organisation - Activate Organisation @@ -594,9 +612,6 @@ Update Organisation - - Organisations - Select Member Roles diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Associations.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Associations.cshtml new file mode 100644 index 0000000..ec06288 --- /dev/null +++ b/SaxoniteCoreWebAdmin/Views/Organisation/Associations.cshtml @@ -0,0 +1,116 @@ +@model Model_OrganisationAssociations +@inject SaxLocaliser Localiser +@{ + /* Organisation Associations - Index */ + ViewData["Title"] = "Organisation Associations"; +} + +
+ + + + @* Filter Panel *@ + @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssociationFilter", @class = "sax-form", @onSubmit = "return false;" })) + { +
+ + @* Header - Page caption, paging controls, actions. *@ +
+
@Localiser["caption.organisation.associations"]
+
+
+ +
+
+ @* Burger menu *@ + +
+
+
+
+ @* Organisation Association filter - Organisation etc. *@ +
+
@Localiser["caption.organisation"]
+
+
+
+ @Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class= "OrganisationId" }) + +
+
+
+
+
+
+ + @* Filter element templates *@ +
+ @* Burger dropdown item template - ul is ignored *@ +
    +
  • XXX
  • +
+
+
+ } + + @* Results Panel *@ +
+
+
+ + @* element templates *@ +
+ @* Organisation Association item template *@ +
+
+
+ @* User name *@ +
+
+
+ @* Burger menu *@ + +
+
+
+
+
+
+
+
+
+
+ @* Association status *@ +
+
+
+
+ @* Burger dropdown item template - ul is ignored *@ +
    +
  • ...
  • +
+
+
+ +
+ +@* Organisation Association components *@ + +@* Select Organisation components *@ + diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Index.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Index.cshtml index d2a4b8c..504fdc4 100644 --- a/SaxoniteCoreWebAdmin/Views/Organisation/Index.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Organisation/Index.cshtml @@ -12,6 +12,7 @@ sax.lbl.create = '@(Localiser.GetJavascriptText("label.create"))'; sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))'; sax.lbl.location = '@(Localiser.GetJavascriptText("label.location"))'; + sax.lbl.associations = '@(Localiser.GetJavascriptText("label.associations"))'; sax.lbl.images = '@(Localiser.GetJavascriptText("label.images"))'; sax.lbl.activate = '@(Localiser.GetJavascriptText("label.activate"))'; @@ -29,7 +30,7 @@ @* Header - Page caption, paging controls, actions. *@
-
@Localiser["organisation.caption.organisations"]
+
@Localiser["caption.organisations"]
@@ -174,14 +175,14 @@ { @Html.HiddenFor(model => model.OrganisationId, new { @class = "OrganisationId" }) } - @* Organisation dialog and form. *@ - - @* Organisation Activation dialog and form. *@ - - @* Organisation Address dialog, form and script. *@ - - @* Organisation Images dialog, form and script. *@ - - @* Select Item dialog and script. *@ + @* Organisation dialog and form *@ + + @* Organisation Activation dialog and form *@ + + @* Organisation Address dialog, form and script *@ + + @* Organisation Images dialog, form and script *@ + + @* Select Item dialog and script *@
diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Members.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Members.cshtml index db8da30..6dc4761 100644 --- a/SaxoniteCoreWebAdmin/Views/Organisation/Members.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Organisation/Members.cshtml @@ -22,7 +22,7 @@ @* Header - Page caption, paging controls, actions. *@
-
@Localiser["organisation.caption.members"]
+
@Localiser["caption.organisation.members"]
@@ -41,12 +41,12 @@
@* Organisation Member filter - Organisation etc. *@
-
@Localiser["organisation.caption.organisation"]
+
@Localiser["caption.organisation"]
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId" }) - +
@@ -112,6 +112,6 @@
- + diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-ActivationDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Activation.cshtml similarity index 100% rename from SaxoniteCoreWebAdmin/Views/Organisation/Panel-ActivationDialog.cshtml rename to SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Activation.cshtml diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationAddressDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Address.cshtml similarity index 100% rename from SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationAddressDialog.cshtml rename to SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Address.cshtml diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Association.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Association.cshtml new file mode 100644 index 0000000..937047d --- /dev/null +++ b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Association.cshtml @@ -0,0 +1,81 @@ +@model Model_OrganisationAssociations +@inject SaxLocaliser Localiser +@* Organisation - Associations components *@ + +@* Organisation Association Id form. *@ +@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmAssociationId" })) +{ + @Html.HiddenFor(model => model.OrganisationId, new { @id = "", @class = "OrganisationId" }) + @Html.HiddenFor(model => model.ItemAssociationId, new { @id = "", @class = "ItemAssociationId" }) +} + +@* Organisation Association dialog. *@ +
+ +
+ @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmOrganisationAssociation", @class = "sax-form", @onSubmit = "return false;" })) + { + @Html.HiddenFor(model => model.ItemAssociationId, new { @id = "", @class = "ItemAssociationId" }) + @Html.HiddenFor(model => model.NewItem, new { @id = "", @class = "NewItem" }) + @Html.HiddenFor(model => model.OrganisationId, new { @id = "", @class = "OrganisationId" }) + + @* Organisation name *@ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + @* Association Type Option *@ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+ + @* Associated Organisation *@ +
+
+
+
+ +
+
+
+
+
+ + +
+
+ +
+
+
+
+
+
+ + } +
+
diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Dialog.cshtml similarity index 100% rename from SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationDialog.cshtml rename to SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Dialog.cshtml diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationImagesDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Images.cshtml similarity index 100% rename from SaxoniteCoreWebAdmin/Views/Organisation/Panel-OrganisationImagesDialog.cshtml rename to SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Images.cshtml diff --git a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-MemberDialog.cshtml b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Member.cshtml similarity index 92% rename from SaxoniteCoreWebAdmin/Views/Organisation/Panel-MemberDialog.cshtml rename to SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Member.cshtml index d102a45..d1d6ee2 100644 --- a/SaxoniteCoreWebAdmin/Views/Organisation/Panel-MemberDialog.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Organisation/Panel-Organisation-Member.cshtml @@ -6,9 +6,9 @@ diff --git a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml index 7ee72ae..22d0f2f 100644 --- a/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml +++ b/SaxoniteCoreWebAdmin/Views/Shared/_Layout.cshtml @@ -134,7 +134,7 @@