This commit is contained in:
2021-07-23 14:01:49 +01:00
parent 10907d3aff
commit 0d7be69e1e
109 changed files with 3161 additions and 943 deletions
@@ -117,6 +117,18 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="account.activate.caption" xml:space="preserve">
<value>Account Activation</value>
</data>
<data name="account.activate.email.subject" xml:space="preserve">
<value>Account Activation</value>
</data>
<data name="account.activate.info" xml:space="preserve">
<value>An activation email will be sent to the selected user inviting them to assign a password and access the platform.</value>
</data>
<data name="account.activate.notify" xml:space="preserve">
<value>Member account has been activated and welcome email sent.</value>
</data>
<data name="account.caption.image.upload" xml:space="preserve">
<value>Image Upload</value>
</data>
@@ -201,6 +213,9 @@
<data name="label.account" xml:space="preserve">
<value>My Account</value>
</data>
<data name="label.activate" xml:space="preserve">
<value>Activate</value>
</data>
<data name="label.add" xml:space="preserve">
<value>Add</value>
</data>
@@ -228,6 +243,9 @@
<data name="label.close" xml:space="preserve">
<value>Close</value>
</data>
<data name="label.comment" xml:space="preserve">
<value>Comment</value>
</data>
<data name="label.contact.details" xml:space="preserve">
<value>Contact details</value>
</data>
@@ -243,6 +261,9 @@
<data name="label.delete" xml:space="preserve">
<value>Delete</value>
</data>
<data name="label.edit" xml:space="preserve">
<value>Edit</value>
</data>
<data name="label.effective" xml:space="preserve">
<value>Effective</value>
</data>
@@ -279,6 +300,12 @@
<data name="label.location" xml:space="preserve">
<value>Location</value>
</data>
<data name="label.member" xml:space="preserve">
<value>Member</value>
</data>
<data name="label.members" xml:space="preserve">
<value>Members</value>
</data>
<data name="label.name" xml:space="preserve">
<value>Name</value>
</data>
@@ -360,6 +387,12 @@
<data name="label.regions.available" xml:space="preserve">
<value>Available regions</value>
</data>
<data name="label.remove" xml:space="preserve">
<value>Remove</value>
</data>
<data name="label.roles" xml:space="preserve">
<value>Roles</value>
</data>
<data name="label.save" xml:space="preserve">
<value>Save</value>
</data>
@@ -403,7 +436,7 @@
<value>Type</value>
</data>
<data name="label.update" xml:space="preserve">
<value>update</value>
<value>Update</value>
</data>
<data name="label.very.good" xml:space="preserve">
<value>Very Good</value>
@@ -441,6 +474,15 @@
<data name="msg.error.system" xml:space="preserve">
<value>System error encountered.</value>
</data>
<data name="msg.item.created" xml:space="preserve">
<value>Item has been created.</value>
</data>
<data name="msg.item.removed" xml:space="preserve">
<value>Item has been removed.</value>
</data>
<data name="msg.item.updated" xml:space="preserve">
<value>Item has been updated.</value>
</data>
<data name="msg.organisation.request.success" xml:space="preserve">
<value>Thank you for registering your organisation.
You will be contacted by email once the details have been confirmed.
@@ -482,6 +524,12 @@ You will then be able to publicise your sporting activities.</value>
<data name="msg.validation.maximum.length" xml:space="preserve">
<value>Value must not exceed {0} characters</value>
</data>
<data name="organisation.caption.member.create" xml:space="preserve">
<value>Add Member</value>
</data>
<data name="organisation.caption.member.update" xml:space="preserve">
<value>Update Member</value>
</data>
<data name="organisation.caption.opportunities" xml:space="preserve">
<value>Organisation Opportunities</value>
</data>
@@ -503,6 +551,21 @@ You will then be able to publicise your sporting activities.</value>
<data name="organisation.caption.organisations" xml:space="preserve">
<value>Organisations</value>
</data>
<data name="organisation.member.remove" xml:space="preserve">
<value>Remove Member</value>
</data>
<data name="organisation.member.remove.confirm" xml:space="preserve">
<value>Are you sure that this member should be removed from the organisation?</value>
</data>
<data name="organisation.member.select.roles" xml:space="preserve">
<value>Member Roles</value>
</data>
<data name="organisation.members" xml:space="preserve">
<value>Organisation Members</value>
</data>
<data name="organisation.members.msg.remove.own.admin.role" xml:space="preserve">
<value>You cannot remove your own 'Member Admin' role.</value>
</data>
<data name="policies.caption.privacy" xml:space="preserve">
<value>Privacy</value>
</data>
@@ -27,7 +27,7 @@ namespace Saxonite.Net.Core.Web.Online.App
{
//-------------------------------------------------------------------
// Data members.
private Dictionary<String, SaxSessionConfig> sessionConfigs = new Dictionary<string, SaxSessionConfig>();
private Dictionary<String, SaxAppConfig> appConfigs = new Dictionary<string, SaxAppConfig>();
private Dictionary<String, SaxEmailConfig> emailConfigs = new Dictionary<string, SaxEmailConfig>();
// Session contexts.
private class SessionContextData
@@ -70,8 +70,8 @@ namespace Saxonite.Net.Core.Web.Online.App
}
public override String SessionCookieName { get { return Sax.Config.Online.Session.Cookie.Name; } }
// Configuration.
public override SaxSessionConfig SessionConfig { get { return sessionConfigs.Values.ToList().getConfigForApplication(); } }
public override SaxEmailConfig EmailConfig { get { return emailConfigs.Values.ToList().getConfigForSession(SessionConfig); } }
public override SaxAppConfig AppConfig { get { return appConfigs.Values.ToList().getConfigForApplication(); } }
public override SaxEmailConfig EmailConfig { get { return emailConfigs.Values.ToList().getConfigForSession(AppConfig); } }
//-------------------------------------------------------------------
// Initialisation.
@@ -102,15 +102,15 @@ namespace Saxonite.Net.Core.Web.Online.App
SaxConfiguration = builder.Build();
// Application configuration.
sessionConfigs = SaxSessionConfigHelper.ExtractSessionConfigs(SaxConfiguration.GetSection("SessionConfigs"));
appConfigs = SaxAppConfigHelper.ExtractAppConfigs(SaxConfiguration.GetSection("AppConfigs"));
emailConfigs = SaxEmailConfigHelper.ExtractEmailConfigs(SaxConfiguration.GetSection("EmailConfigs"));
LoggingRootFolder = SessionConfig.Logging.RootFolder;
LoggingRootFolder = AppConfig.Logging.RootFolder;
// Application instance.
if (SessionConfig.Instance.EqualsCI("Dev")) instanceType = Sax.InstanceType.Dev;
else if (SessionConfig.Instance.ContainsCI("Q")) instanceType = Sax.InstanceType.QC;
else if (SessionConfig.Instance.ContainsCI("UAT")) instanceType = Sax.InstanceType.UAT;
else if (SessionConfig.Instance.EqualsCI("PreProd")) instanceType = Sax.InstanceType.UAT;
if (AppConfig.Instance.EqualsCI("Dev")) instanceType = Sax.InstanceType.Dev;
else if (AppConfig.Instance.ContainsCI("Q")) instanceType = Sax.InstanceType.QC;
else if (AppConfig.Instance.ContainsCI("UAT")) instanceType = Sax.InstanceType.UAT;
else if (AppConfig.Instance.EqualsCI("PreProd")) instanceType = Sax.InstanceType.UAT;
// Initialise hard-coded logging path.
if (StringUtil.IsEmpty(LoggingRootFolder))
@@ -124,9 +124,9 @@ namespace Saxonite.Net.Core.Web.Online.App
// Configure database connection.
SacsDatabaseConsole.OdbcConfig config = new SacsDatabaseConsole.OdbcConfig();
config.location = SessionConfig.CoreDatabase.Location;
config.user = SessionConfig.CoreDatabase.User;
config.pword = SessionConfig.CoreDatabase.Password;
config.location = AppConfig.CoreDatabase.Location;
config.user = AppConfig.CoreDatabase.User;
config.pword = AppConfig.CoreDatabase.Password;
SacsDatabase coreDatabase = SacsDatabaseConsole.OpenOdbcDatabase(config);
if (coreDatabase.HasErrorState())
SaLogger.Warn(fn + " Database initialisation error: " + coreDatabase.ErrorStateMessage);
@@ -12,6 +12,8 @@ using Saxonite.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Utils;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Dbas;
namespace Saxonite.Net.Core.Web.Online.Controllers
{
@@ -23,20 +25,23 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
//-------------------------------------------------------------------
// Account - Get Organisations.
//-------------------------------------------------------------------
private class ProfileOrganisationResponseData
private class ProfileOrganisationData
{
public ProfileOrganisationResponseData(SaxOrganisation organisation)
{
Name = organisation.Name;
}
public String Name { get; }
public long Id { get; set; }
public String Name { get; set; }
public long SportId { get; set; }
public String SportName { get; set; }
public long RegionId { get; set; }
public String RegionName { get; set; }
public long MemberCount { get; set; }
public long OpportunityCount { get; set; }
}
private class AjaxResponse_ProfileOrganisationsData : AjaxResponse_Data
{
// Construction.
public AjaxResponse_ProfileOrganisationsData(SaxModel_Online model) : base(model) { }
// Organisation list.
public List<ProfileOrganisationResponseData> Organisations { get; } = new List<ProfileOrganisationResponseData>();
public List<ProfileOrganisationData> Organisations { get; } = new List<ProfileOrganisationData>();
}
// Ajax request.
[HttpPost]
@@ -48,40 +53,68 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
String messageTitle = Localiser["account.caption.profile.organisations"];
// Validate session and referrer.
if (!ValidReferer)
return Forbid();
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Retrieve users organisations.
// Query organisations that user is a member of.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.OrganisationStatusCat = SaxOrganisation.StatusCat.ActiveOnly;
prmUserOrganisation.OrganisationMembersOnly = true;
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
List<SaxUserOrganisation> userOrganisations = AccountMgr.GetUserOrganisationList(prmUserOrganisation);
List<SysId> organisationIds = userOrganisations.GetOrganisationIds();
// Retrieve the organisation details.
List<SaxOrganisation> organisations = new List<SaxOrganisation>();
if (!organisationIds.IsEmpty())
// Item columns.
ColumnDfn colId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Id);
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
ColumnDfn colOrganisationSportId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_SportId);
ColumnDfn colOrganisationSportName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Sport_Name);
ColumnDfn colOrganisationRegionId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_RegionId);
ColumnDfn colOrganisationRegionName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Region_Name);
ColumnDfn colMemberCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Member_Count);
ColumnDfn colOpportunityCount = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Opportunity_Count);
ColumnDfn colStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Status);
ColumnDfn colCreatedOn = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.CreateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
SaxOrganisation.Params prmOrganisation = new SaxOrganisation.Params();
prmOrganisation.IdsIncluded.AddRange(organisationIds);
prmOrganisation.StatusCat = SaxOrganisation.StatusCat.ActiveOnly;
prmOrganisation.SortColumns.Add(AccountMgr.GetOrganisationColumnDfn(SaxOrganisation.Column.Name));
organisations.AddRange(AccountMgr.GetOrganisationList(prmOrganisation));
}
colId, colOrganisationId , colOrganisationName,
colOrganisationSportId, colOrganisationSportName,
colOrganisationRegionId, colOrganisationRegionName,
colMemberCount, colOpportunityCount,
colStatus, colStatus, colCreatedOn
};
// Add the organisations to the response.
foreach (SaxUserOrganisation userOrganisation in userOrganisations)
// Sort columns.
colCreatedOn.SortAscending = false;
prmUserOrganisation.SortColumns.Add(colOrganisationName);
// Query items.
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmUserOrganisation))
{
SaxOrganisation organisation = organisations.GetOrganisationById(userOrganisation.OrganisationId);
if (organisation == null) continue;
ProfileOrganisationResponseData organisationData = new ProfileOrganisationResponseData(organisation);
responseData.Organisations.Add(organisationData);
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
ProfileOrganisationData organisationData = new ProfileOrganisationData()
{
Id = values.GetLong(colId.DataName),
Name = values.GetString(colOrganisationName.DataName),
SportId = values.GetLong(colOrganisationSportId.DataName),
SportName = values.GetString(colOrganisationSportName.DataName),
RegionId = values.GetLong(colOrganisationRegionId.DataName),
RegionName = values.GetString(colOrganisationRegionName.DataName),
MemberCount = values.GetLong(colMemberCount.DataName),
OpportunityCount = values.GetLong(colOpportunityCount.DataName)
};
responseData.Organisations.Add(organisationData);
}
}
if (model.Paging.IsPaged)
model.Paging.ItemCount = (ushort)responseData.Organisations.Count;
// Complete response.
responseData.SetPaging(model);
responseData.Success = true;
return Json(responseData);
}
@@ -276,7 +276,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!AccountMgr.InsertUserSport(userSport, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert user sport: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
}
else
@@ -284,7 +284,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!AccountMgr.UpdateUserSport(userSport, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update user sport [Id:" + SysId.ToString(userSport.Id) + "]: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
}
@@ -36,7 +36,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Check for 'Keep Logged In' cookie.
// NB Only allowed if there isn't a current user session.
if (!ValidUserSession && SessionConfig.Security.SignIn.KeepLoggedIn.Allowed)
if (!ValidUserSession && AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
{
String encryptedParams = GetRequestCookie(CookieName_KeepLoggedIn);
KeepLoggedInParams keepLoggedInParams = ExtractKeepLoggedInParams(encryptedParams);
@@ -454,7 +454,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!ActivityMgr.InsertJournalistArticle(article, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert article: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ActivityMgr.ErrorStateMessage));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
}
@@ -512,7 +512,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!ActivityMgr.UpdateJournalistArticle(article, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update article [Id:" + SysId.ToString(article.Id) + "]: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ActivityMgr.ErrorStateMessage));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
// Store Article Activity Index data.
@@ -0,0 +1,707 @@
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.Email;
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 Saxonite.Net.Standard.Base.Helpers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Online.Controllers
{
//=======================================================================
// Online Organisation Controller - Members - Ajax actions.
//=======================================================================
partial class OrganisationController
{
//-------------------------------------------------------------------
// Organisation Member data.
private class MemberData_List : AjaxResponse_Data.ItemData_Base
{
public String UserAccountId { get; set; }
public bool? CurrentUser { get; set; } = null;
public String EmailAddress { get; set; }
public String DisplayName { get; set; }
public List<String> RoleCodes { get; set; } = new List<string>();
public List<CodeDesc> Roles { get; set; } = new List<CodeDesc>();
public String AdminComment { get; set; }
}
private class MemberData_Full : MemberData_List
{
public String Title { get; set; }
public String FirstName { get; set; }
public String LastName { get; set; }
}
private void PopulateMemberResponseData(Model_Organisation_Members model, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation, MemberData_List data)
{
data.Id = SysId.ToString(userOrganisation.Id);
data.UserAccountId = SysId.ToString(userOrganisation.UserAccountId);
if (userOrganisation.UserAccountId.Equals(SessionData.User.UserAccountId)) data.CurrentUser = true;
data.EmailAddress = userAccount.EmailAddress;
data.DisplayName = userAccount.GetDisplayName();
data.RoleCodes.Clear();
data.Roles.Clear();
foreach (String memberRoleCode in userOrganisation.GetOrganisationRoleCodes())
{
if (StringUtil.IsEmpty(memberRoleCode.Trim())) continue;
Sax.OrganisationRole organisationRole = (Sax.OrganisationRole)OrganisationRoleCodes.GetTypeForCode(memberRoleCode);
if (organisationRole <= 0 || organisationRole == Sax.OrganisationRole.Member) continue;
data.RoleCodes.Add(memberRoleCode);
data.Roles.Add(memberRoleCode, Localiser.GetOrganisationRoleCaption(organisationRole));
}
data.AdminComment = userOrganisation.AdminComment;
// NB UserAccount status (not UserOrganisation).
data.StatusCode = userAccount.StatusCode;
data.StatusDesc = userAccount.StatusDesc;
data.CreatedOnFmt = Localiser.FormatDate(userOrganisation.CreateStamp.On);
}
private void PopulateMemberResponseData(Model_Organisation_Members model, SaxUserOrganisation userOrganisation, SaxUserAccount userAccount, SaxOrganisation organisation, MemberData_Full data)
{
PopulateMemberResponseData(model, userOrganisation, userAccount, organisation, data as MemberData_List);
data.Title = userAccount.Title;
data.FirstName = userAccount.FirstName;
data.LastName = userAccount.LastName;
}
//-------------------------------------------------------------------
// Get Member List ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_MemberList : AjaxResponse_Data
{
// Construction.
public AjaxResponse_MemberList(SaxModel_Online model) : base(model) { }
// Member list.
public List<MemberData_List> Members { get; } = new List<MemberData_List>();
// User profile.
public class UserData
{
public bool CanManage { get; set; }
}
public UserData User { get; } = new UserData();
// Reference data.
public List<CodeDesc> Titles { get; } = new List<CodeDesc>();
public List<CodeDesc> MemberRoles { get; } = new List<CodeDesc>();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Organisation/Ajax/GetMemberList")]
[Route("Organisation/Ajax/GetMembers")]
public IActionResult Ajax_GetMemberList(Model_Organisation_Members model)
{
String fn = GetType().Name + ".Ajax_GetMemberList";
String messageTitle = Localiser["organisation.members"];
AjaxResponse_MemberList responseData = new AjaxResponse_MemberList(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Organisation.
SysId organisationId = model.Filter.OrganisationId.ToSysId();
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Member list. OrganisationId: '" + model.Filter.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (organisation != null)
{
// Store filter data.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
// Reference data - titles.
foreach (TypeCodeDesc title in SaxSystem.GetCodesOfType(Sax.CodeType.Title))
// ToDo Title translations.
responseData.Titles.Add(title.Code, title.Desc);
// Reference data - member roles.
foreach (TypeCodeDesc memberRole in OrganisationRoleCodes.FindAll( item => item.Type != (int)Sax.OrganisationRole.Member))
responseData.MemberRoles.Add(memberRole.Code, Localiser.GetOrganisationRoleCaption((Sax.OrganisationRole)memberRole.Type));
// Session User roles.
responseData.User.CanManage = AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisationId, Sax.OrganisationRole.MemberAdmin);
// Item filter.
SaxUserOrganisation.Params prmMember = new SaxUserOrganisation.Params();
prmMember.OrganisationIdsIncluded.Add(organisationId);
prmMember.UserAccountStatusCat = responseData.User.CanManage ? SaxUserAccount.StatusCat.AwaitingOrActive : SaxUserAccount.StatusCat.ActiveOnly;
prmMember.OrganisationMembersOnly = true;
//prmMember.MemberFilter = model.Filter.Member;
prmMember.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
model.Paging.ItemTotal = (ulong)AccountMgr.GetUserOrganisationCount(prmMember);
model.PopulatePagingTo(prmMember.ResultsPaging);
// Item columns.
ColumnDfn colId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Id);
ColumnDfn colUserAccountId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.UserAccountId);
ColumnDfn colEmailAddress = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_EmailAddress) : new ColumnDfn(-1, "");
ColumnDfn colDisplayName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_DisplayName);
ColumnDfn colOrganisationRoleCodes = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationRoleCodes) : new ColumnDfn(-1, "");
ColumnDfn colUserStatus = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.User_Status);
ColumnDfn colAdminComment = responseData.User.CanManage ? AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.AdminComment) : new ColumnDfn(-1, "");
ColumnDfn colCreatedOn = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.CreateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId, colUserAccountId , colEmailAddress, colDisplayName,
colOrganisationRoleCodes, colUserStatus,
colAdminComment, colCreatedOn
};
// Sort columns.
colCreatedOn.SortAscending = false;
prmMember.SortColumns.Add(colDisplayName);
// Query items.
using (DbResultSet resultSet = AccountMgr.ExecuteUserOrganisationQuery(columns, prmMember))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
MemberData_List memberData = new MemberData_List()
{
Id = values.GetString(colId.DataName),
UserAccountId = values.GetString(colUserAccountId.DataName),
EmailAddress = values.GetString(colEmailAddress.DataName),
DisplayName = AccountMgr.GetUserOrganisationDataValue(colDisplayName, values).ToString(),
CreatedOnFmt = Localiser.FormatDate(values.GetDateTime(colCreatedOn.DataName)),
AdminComment = values.GetString(colAdminComment.DataName),
// NB UserAccount status (not UserOrganisation).
StatusCode = values.GetString(colUserStatus.DataName),
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colUserStatus.DataName))
};
if (memberData.UserAccountId.ToSysId().Equals(SessionData.User.UserAccountId)) memberData.CurrentUser = true;
String memberRoleCodes = values.GetString(colOrganisationRoleCodes.DataName);
foreach (String memberRoleCode in StringListUtil.Split(memberRoleCodes, SaxUserOrganisation.UserOrgnisationRoleDelim))
{
if (StringUtil.IsEmpty(memberRoleCode.Trim())) continue;
Sax.OrganisationRole organisationRole = (Sax.OrganisationRole)OrganisationRoleCodes.GetTypeForCode(memberRoleCode);
if (organisationRole <= 0 || organisationRole == Sax.OrganisationRole.Member) continue;
memberData.RoleCodes.Add(memberRoleCode);
memberData.Roles.Add(memberRoleCode, Localiser.GetOrganisationRoleCaption(organisationRole));
}
responseData.Members.Add(memberData);
}
}
}
if (model.Paging.IsPaged)
model.Paging.ItemCount = (ushort)responseData.Members.Count;
// Complete response.
responseData.SetPaging(model);
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Get Member ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_Member : AjaxResponse_Data
{
// Construction.
public AjaxResponse_Member(SaxModel_Online model) : base(model) { }
// Member details.
public MemberData_Full Member { get; } = new MemberData_Full();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Organisation/Ajax/GetMember")]
public IActionResult Ajax_GetMember(Model_Organisation_Members model)
{
String fn = GetType().Name + ".Ajax_GetMember";
String messageTitle = Localiser["label.member"];
AjaxResponse_Member responseData = new AjaxResponse_Member(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Identify item.
SysId memberId = model.MemberId.ToSysId();
if (!SysId.IsValid(memberId))
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
using (SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(memberId))
{
if (userOrganisation == null)
{
SaLogger.Warn(fn + " Failed to retrieve Organisation Member for Id: '" + model.MemberId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Validate organisation.
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId))
{
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " Organisation for Member. Id: '" + userOrganisation.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Session User roles.
bool userCanManageMembers = AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisation.Id, Sax.OrganisationRole.MemberAdmin);
// Validate user account.
using (SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId))
{
bool userActive = userAccount.IsStatusActive || (userAccount.IsStatusAwaiting && userCanManageMembers);
if (userAccount == null || !userActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " User Account for Member. Id: '" + userOrganisation.UserAccountId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Make a note of the selected Organisation.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
PopulateMemberResponseData(model, userOrganisation, userAccount, organisation, responseData.Member);
}
}
}
// Construct response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Store Member ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_StoreMember : AjaxResponse_Data
{
// Construction.
public AjaxResponse_StoreMember(SaxModel_Online model) : base(model) { }
// Member details.
public MemberData_Full Member { get; } = new MemberData_Full();
// Feedback.
public bool? MemberNameRequired { get; set; } = null;
}
[HttpPost]
[Route("Organisation/Ajax/StoreMember")]
public IActionResult Ajax_StoreMember(Model_Organisation_Members model)
{
String fn = GetType().Name + ".Ajax_StoreMember";
String messageTitle = Localiser["label.member"];
AjaxResponse_StoreMember responseData = new AjaxResponse_StoreMember(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Validate item properties.
model.ValidateMemberData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
//---------------------------------------------------------------
// User Organisation identifiers.
// New Member:
// Organisation Id [MemberOrganisationId].
// Email address [MemberEmailAddress].
// Existing member:
// User Organisation Id [MemberId].
//---------------------------------------------------------------
// Validate Member against Id against 'Exists' flag.
SysId memberId = model.MemberId.ToSysId();
bool memberExists = StringUtil.ToBool(model.MemberExists);
if (memberExists && !SysId.IsValid(memberId))
{
SaLogger.Warn(fn + " Id not specified for existing User Organisation.");
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
if (!memberExists && SysId.IsValid(memberId))
{
SaLogger.Warn(fn + " Id specified for new User Organisation: '" + model.MemberId + "'");
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Retrieve existing item.
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(memberId);
disposableItems.Add(userOrganisation);
if (userOrganisation == null && SysId.IsValid(memberId))
{
SaLogger.Warn(fn + " Failed to retrieve User Organisation for Id: '" + model.MemberId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Validate the Organisation.
SysId organisationId = userOrganisation != null ? userOrganisation.OrganisationId : model.MemberOrganisationId.ToSysId();
if (!SysId.IsValid(organisationId))
{
SaLogger.Warn(fn + " Organisation Id not specified for Member.");
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 User Organisation. OrganisationId: '" + model.MemberOrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (userOrganisation != null && !userOrganisation.OrganisationId.Equals(organisationId))
{
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for User Organisation. Expected: " + userOrganisation.OrganisationId + ". Found: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Ensure that the user has the correct role to update Members for this organisation.
bool userCanManageMembers = AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisationId, Sax.OrganisationRole.MemberAdmin);
if (!userCanManageMembers)
{
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Validate the User Account for an existing member.
SaxUserAccount userAccount = null;
if (userOrganisation != null)
{
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
disposableItems.Add(userAccount);
bool userActive = userAccount.IsStatusActive || (userAccount.IsStatusAwaiting && userCanManageMembers);
if (userAccount == null || !userActive)
{
SaLogger.Warn(fn + " " + (userAccount == null ? "Invalid" : "Inactive") + " User Account for User Organisation. UserAccountId: '" + userOrganisation.UserAccountId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (userOrganisation != null && !userOrganisation.UserAccountId.Equals(userAccount.Id))
{
SaLogger.Warn(fn + " Inconsistent User Account Id specified for User Organisation. Expected: " + userOrganisation.UserAccountId + ". Found: " + userAccount.Id);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
// New member - Lookup user by email and create new account if needed.
if (userAccount == null)
{
// Check if account exists for email.
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.MemberEmailAddress);
if (userAccount != null)
{
// Existing User Account - get User Organisation if available.
userOrganisation = AccountMgr.GetUserOrganisationByUserOrganisation(userAccount.Id, organisation.Id);
disposableItems.Add(userOrganisation);
}
else
{
// If name hasn't been specified, return to page to complete details.
if (!StringUtil.ToBool(model.MemberNameSupplied))
{
responseData.SetControlError(nameof(model.MemberFirstName), Localiser["msg.validation.mandatory.value"]);
responseData.SetControlError(nameof(model.MemberLastName), Localiser["msg.validation.mandatory.value"]);
responseData.MemberNameRequired = true;
responseData.Success = true;
return Json(responseData);
}
// Create new User Account.
userAccount = AccountMgr.CreateUserAccount();
userAccount.EmailAddress = model.MemberEmailAddress;
userAccount.Status = SaStatus.Awaiting;
}
disposableItems.Add(userAccount);
}
// Store user account.
if (StringUtil.ToBool(model.MemberNameSupplied))
{
if (model.MemberTitle != null)
userAccount.Title = model.MemberTitle;
if (model.MemberFirstName != null)
userAccount.FirstName = model.MemberFirstName;
if (model.MemberLastName != null)
userAccount.LastName = model.MemberLastName;
}
if (!SysId.IsValid(userAccount.Id))
{
if (!AccountMgr.InsertUserAccount(userAccount, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
}
else
{
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
}
// Create new item if required.
if (userOrganisation == null)
{
userOrganisation = AccountMgr.CreateUserOrganisation(userAccount.Id, organisation.Id);
disposableItems.Add(userOrganisation);
}
// User Organisation Roles.
if (model.MemberRoleCodes != null)
userOrganisation.OrganisationRoles = SaxUserOrganisation.GetOrganisationRolesFromCodes(model.GetMemberRoleCodes());
// Ensure user has member role.
userOrganisation.AddOrganisationRole(Sax.OrganisationRole.Member);
// Validate roles.
if (userOrganisation.UserAccountId.Equals(SessionData.User.UserAccountId))
{
// User is modifying their own member.
if (!userOrganisation.HasOrganisationRole(Sax.OrganisationRole.MemberAdmin))
{
SaLogger.Warn(fn + " Unable to store member - user is attempting to remove their own 'Member Admin' role.");
return Json(responseData.SetMessage(messageTitle, Localiser["organisation.members.msg.remove.own.admin.role"]));
}
}
// User organisation properties.
if (model.MemberAdminComment != null)
userOrganisation.AdminComment = model.MemberAdminComment;
userOrganisation.Status = SaStatus.Active;
// Store item.
if (!SysId.IsValid(userOrganisation.Id))
{
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert User Organisation: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
}
else
{
if (!AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update User Organisation [Id:" + SysId.ToString(userOrganisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
}
// Construct response.
PopulateMemberResponseData(model, userOrganisation, userAccount, organisation, responseData.Member);
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Activate Member ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_ActivateMember : AjaxResponse_Data
{
// Construction.
public AjaxResponse_ActivateMember(SaxModel_Online model) : base(model) { }
// Member details.
public MemberData_Full Member { get; } = new MemberData_Full();
}
[HttpPost]
[Route("Organisation/Ajax/ActivateMember")]
public IActionResult Ajax_ActivateMember(Model_Organisation_Members model)
{
String fn = GetType().Name + ".Ajax_ActivateMember";
String messageTitle = Localiser["label.member"];
AjaxResponse_ActivateMember responseData = new AjaxResponse_ActivateMember(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Retrieve User Organisation [MemberId).
SysId userOrganisationId = model.MemberId.ToSysId();
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
disposableItems.Add(userOrganisation);
if (userOrganisation == null || !userOrganisation.IsStatusActive)
{
SaLogger.Warn(fn + " User Organisation not found or not active. Id: " + SysId.ToString(userOrganisationId));
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve the Organisation.
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
disposableItems.Add(organisation);
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " Organisation not found or not active. Id: " + SysId.ToString(userOrganisation.OrganisationId));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Ensure that the user has the correct role to update Members for this organisation.
bool userCanManageMembers = AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisation.Id, Sax.OrganisationRole.MemberAdmin);
if (!userCanManageMembers)
{
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisation.Id);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve User Account.
SaxUserAccount userAccount = null;
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
disposableItems.Add(userAccount);
if (userAccount == null)
{
SaLogger.Warn(fn + " Failed to retrieve User Account. Id: " + userOrganisation.UserAccountId);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (!userAccount.IsStatusAwaiting)
{
SaLogger.Warn(fn + " User Account is not awaiting. Id: " + userOrganisation.UserAccountId + ". Status: " + userAccount.StatusDesc);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Update user's status.
userAccount.Status = SaStatus.Active;
if (AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
{
// Send activation email.
SaEmailData emailData = new SaEmailData();
emailData.Config = EmailConfig;
emailData.AddressesTo.Add(userAccount.EmailAddress);
emailData.Subject = Localiser["account.activate.email.subject"];
PopulateAccountActivatedEmailBody(emailData, userAccount);
if (EmailConsole.SendEmail(emailData))
SaLogger.Info(fn + " User Activation email sent to " + userAccount.EmailAddress, true);
else SaLogger.Warn(fn + " Failed to send User Activation email to " + userAccount.EmailAddress);
// Treat the activation as successful regardless of whether the email was sent.
responseData.SetNotification(messageTitle, Localiser["account.activate.notify"]);
}
else
{
SaLogger.Warn(fn + " Failed to insert User Account: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
// Construct response.
PopulateMemberResponseData(model, userOrganisation, userAccount, organisation, responseData.Member);
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
private void PopulateAccountActivatedEmailBody(SaEmailData emailData, SaxUserAccount userAccount)
{
// Will need to handle culture (language/country) as and when introduced.
emailData.MessageBody = SaxResourceHelper.GetTextResource(SaxResourceHelper.TextResource.Email_Security_AccountActivated_Html);
emailData.HtmlBody = true;
// Replace dynamic tags.
EmailConsole.ReplaceDynamicEmailBodyTags(emailData, null, userAccount);
// Replace dynamic tag for link back to change password page.
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, ""));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
}
//-------------------------------------------------------------------
// Remove Member ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_RemoveMember : AjaxResponse_Data
{
// Construction.
public AjaxResponse_RemoveMember(SaxModel_Online model) : base(model) { }
// Member details.
public MemberData_Full Member { get; } = new MemberData_Full();
}
[HttpPost]
[Route("Organisation/Ajax/RemoveMember")]
public IActionResult Ajax_RemoveMember(Model_Organisation_Members model)
{
String fn = GetType().Name + ".Ajax_RemoveMember";
String messageTitle = Localiser["label.member"];
AjaxResponse_RemoveMember responseData = new AjaxResponse_RemoveMember(model);
// Validate session and referrer.
if (!ValidReferer) return Forbid();
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
// Retrieve User Organisation [MemberId).
SysId userOrganisationId = model.MemberId.ToSysId();
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId);
disposableItems.Add(userOrganisation);
if (userOrganisation == null || !userOrganisation.IsStatusActive)
{
SaLogger.Warn(fn + " User Organisation not found or not active. Id: " + SysId.ToString(userOrganisationId));
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve the Organisation.
SaxOrganisation organisation = AccountMgr.GetOrganisationById(userOrganisation.OrganisationId);
disposableItems.Add(organisation);
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " Organisation not found or not active. Id: " + SysId.ToString(userOrganisation.OrganisationId));
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Ensure that the user has the correct role to update Members for this organisation.
bool userCanManageMembers = AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisation.Id, Sax.OrganisationRole.MemberAdmin);
if (!userCanManageMembers)
{
SaLogger.Warn(fn + " User doesn't have 'Member Admin' role for Organisation Id: " + organisation.Id);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve User Account.
SaxUserAccount userAccount = null;
userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId);
disposableItems.Add(userAccount);
if (userAccount == null)
{
SaLogger.Warn(fn + " Failed to retrieve User Account. Id: " + userOrganisation.UserAccountId);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (!userAccount.IsStatusAwaiting && !userAccount.IsStatusActive)
{
SaLogger.Warn(fn + " User Account is not awaiting or active. Id: " + userOrganisation.UserAccountId);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Remove User Organisation roles.
userOrganisation.ClearOrganisationRoles();
if (AccountMgr.UpdateUserOrganisation(userOrganisation, DbUpdateInfo))
{
responseData.SetNotification(messageTitle, Localiser["msg.item.removed"]);
}
else
{
SaLogger.Warn(fn + " Failed to update User Organisation: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
// Construct response.
PopulateMemberResponseData(model, userOrganisation, userAccount, organisation, responseData.Member);
}
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -21,9 +21,8 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
{
//-------------------------------------------------------------------
// Organisation Opportunity data.
private class OpportunityData_List
private class OpportunityData_List : AjaxResponse_Data.ItemData_Base
{
public String Id { get; set; }
public String TypeCode { get; set; }
public String TypeDesc { get; set; }
public String Position { get; set; }
@@ -32,9 +31,6 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
public String SportCaption { get; set; }
public String PublishedOnFmt { get; set; }
public String ExpiresOnFmt { get; set; }
public String CreatedOnFmt { get; set; }
public String StatusCode { get; set; }
public String StatusDesc { get; set; }
}
private class OpportunityData_Full : OpportunityData_List
{
@@ -52,9 +48,9 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
data.Outline = opportunity.Outline;
data.RegionCaption = model.GetRegionCaption(opportunity.RegionIdPrimary);
data.SportCaption = model.GetSportCaption(opportunity.SportIdPrimary);
data.CreatedOnFmt = DateUtil.Format(opportunity.CreateStamp.On, "d-MMM-yyyy");
data.PublishedOnFmt = DateUtil.Format(opportunity.PublishedAt, "d-MMM-yyyy");
data.ExpiresOnFmt = DateUtil.Format(opportunity.ExpiresAt, "d-MMM-yyyy");
data.CreatedOnFmt = Localiser.FormatDate(opportunity.CreateStamp.On);
data.PublishedOnFmt = Localiser.FormatDate(opportunity.PublishedAt);
data.ExpiresOnFmt = Localiser.FormatDate(opportunity.ExpiresAt);
data.StatusCode = opportunity.StatusCode;
data.StatusDesc = opportunity.StatusDesc;
}
@@ -103,88 +99,93 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
// Organisation.
SysId organisationId = model.Filter.OrganisationId.ToSysId();
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
if (organisation == null || !organisation.IsStatusActive)
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId))
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity list. OrganisationId: '" + model.Filter.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (organisation != null)
{
// Store filter data.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
// Reference data - opportunity types.
foreach (TypeCodeDesc opportunityType in OpportunityTypeCodes)
responseData.OpportunityTypes.Add(opportunityType.Code, Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)opportunityType.Type));
// User organisation.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation);
// User details.
responseData.User.CanManage = userOrganisation?.OrganisationRoles.Contains(Sax.OrganisationRole.OpportunityAdmin) ?? false;
// Item filter.
SaxOrganisationOpportunity.Params prmOpportunity = new SaxOrganisationOpportunity.Params();
prmOpportunity.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmOpportunity.OrganisationIdsIncluded.Add(organisationId);
prmOpportunity.OpportunityFilter = model.Filter.Opportunity;
prmOpportunity.StatusCat = SaxOrganisationOpportunity.StatusCat.NotDeleted;
model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationOpportunityCount(prmOpportunity);
model.PopulatePagingTo(prmOpportunity.ResultsPaging);
// Item columns.
ColumnDfn colId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Id);
ColumnDfn colOpportunityTypeCode = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.OpportunityTypeCode);
ColumnDfn colPosition = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Position);
ColumnDfn colOutline = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Outline);
ColumnDfn colRegionId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.RegionIdPrimary);
ColumnDfn colRegionName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Region_Name);
ColumnDfn colSportId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.SportIdPrimary);
ColumnDfn colSportName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Sport_Name);
ColumnDfn colPublishedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.PublishedAt_Date);
ColumnDfn colExpiresOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.ExpiresAt_Date);
ColumnDfn colStatus = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Status);
ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.CreateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
if (organisation == null || !organisation.IsStatusActive)
{
colId, colOpportunityTypeCode, colPosition, colOutline,
colRegionId, colRegionName, colSportId, colSportName,
colPublishedOn, colExpiresOn,
colStatus, colCreatedOn
};
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity list. OrganisationId: '" + model.Filter.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Sort columns.
colCreatedOn.SortAscending = false;
prmOpportunity.SortColumns.Add(colCreatedOn);
// Query items.
using (DbResultSet resultSet = ActivityMgr.ExecuteOrganisationOpportunityQuery(columns, prmOpportunity))
if (organisation != null)
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
// Store filter data.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
// Reference data - opportunity types.
foreach (TypeCodeDesc opportunityType in OpportunityTypeCodes)
responseData.OpportunityTypes.Add(opportunityType.Code, Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)opportunityType.Type));
// User organisation.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
prmUserOrganisation.UserAccountStatusCat = SaxUserAccount.StatusCat.ActiveOnly;
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
using (SaxUserOrganisation userOrganisation = AccountMgr.GetUserOrganisation(prmUserOrganisation))
{
NamedValue.Map values = resultSet.GetRecordValues();
OpportunityData_List opportunityData = new OpportunityData_List()
// User details.
responseData.User.CanManage = userOrganisation?.HasOrganisationRole(Sax.OrganisationRole.OpportunityAdmin) ?? false;
// Item filter.
SaxOrganisationOpportunity.Params prmOpportunity = new SaxOrganisationOpportunity.Params();
prmOpportunity.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmOpportunity.OrganisationIdsIncluded.Add(organisationId);
prmOpportunity.OpportunityFilter = model.Filter.Opportunity;
prmOpportunity.StatusCat = SaxOrganisationOpportunity.StatusCat.NotDeleted;
model.Paging.ItemTotal = (ulong)ActivityMgr.GetOrganisationOpportunityCount(prmOpportunity);
model.PopulatePagingTo(prmOpportunity.ResultsPaging);
// Item columns.
ColumnDfn colId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Id);
ColumnDfn colOpportunityTypeCode = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.OpportunityTypeCode);
ColumnDfn colPosition = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Position);
ColumnDfn colOutline = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Outline);
ColumnDfn colRegionId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.RegionIdPrimary);
ColumnDfn colRegionName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Region_Name);
ColumnDfn colSportId = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.SportIdPrimary);
ColumnDfn colSportName = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Sport_Name);
ColumnDfn colPublishedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.PublishedAt_Date);
ColumnDfn colExpiresOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.ExpiresAt_Date);
ColumnDfn colStatus = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.Status);
ColumnDfn colCreatedOn = ActivityMgr.GetOrganisationOpportunityColumnDfn(SaxOrganisationOpportunity.Column.CreateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
Id = values.GetString(colId.DataName),
TypeCode = values.GetString(colOpportunityTypeCode.DataName),
TypeDesc = Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(values.GetString(colOpportunityTypeCode.DataName))),
Position = values.GetString(colPosition.DataName),
Outline = values.GetString(colOutline.DataName),
RegionCaption = model.GetRegionCaption(values.GetString(colRegionId.DataName).ToSysId()),
SportCaption = model.GetSportCaption(values.GetString(colSportId.DataName).ToSysId()),
CreatedOnFmt = DateUtil.Format(values.GetDateTime(colCreatedOn.DataName), "d-MMM-yyyy"),
PublishedOnFmt = DateUtil.Format(values.GetDateTime(colPublishedOn.DataName), "d-MMM-yyyy"),
ExpiresOnFmt = DateUtil.Format(values.GetDateTime(colExpiresOn.DataName), "d-MMM-yyyy"),
StatusCode = values.GetString(colStatus.DataName),
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
colId, colOpportunityTypeCode, colPosition, colOutline,
colRegionId, colRegionName, colSportId, colSportName,
colPublishedOn, colExpiresOn,
colStatus, colCreatedOn
};
responseData.Opportunities.Add(opportunityData);
// Sort columns.
colCreatedOn.SortAscending = false;
prmOpportunity.SortColumns.Add(colCreatedOn);
// Query items.
using (DbResultSet resultSet = ActivityMgr.ExecuteOrganisationOpportunityQuery(columns, prmOpportunity))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
OpportunityData_List opportunityData = new OpportunityData_List()
{
Id = values.GetString(colId.DataName),
TypeCode = values.GetString(colOpportunityTypeCode.DataName),
TypeDesc = Localiser.GetOpportunityTypeCaption((Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(values.GetString(colOpportunityTypeCode.DataName))),
Position = values.GetString(colPosition.DataName),
Outline = values.GetString(colOutline.DataName),
RegionCaption = model.GetRegionCaption(values.GetString(colRegionId.DataName).ToSysId()),
SportCaption = model.GetSportCaption(values.GetString(colSportId.DataName).ToSysId()),
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))
};
responseData.Opportunities.Add(opportunityData);
}
}
}
}
}
@@ -228,26 +229,32 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId);
if (opportunity == null)
using (SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId))
{
SaLogger.Warn(fn + " Failed to retrieve Organisation Opportunity for Id: '" + model.OpportunityId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
if (opportunity == null)
{
SaLogger.Warn(fn + " Failed to retrieve Organisation Opportunity for Id: '" + model.OpportunityId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Validate organisation.
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(opportunity.OrganisationId))
{
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity. OrganisationId: '" + opportunity.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Make a note of the selected Organisation.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
// Construct response.
PopulateOpportunityResponseData(model, opportunity, responseData.Opportunity);
}
}
// Validate organisation.
SaxOrganisation organisation = AccountMgr.GetOrganisationById(opportunity.OrganisationId);
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity. OrganisationId: '" + opportunity.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Make a note of the selected Organisation.
SessionData_Online.Filter.SetMemberOrganisation(organisation);
// Construct response.
PopulateOpportunityResponseData(model, opportunity, responseData.Opportunity);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
@@ -288,81 +295,93 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve existing item.
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId);
if (opportunity == null && SysId.IsValid(opportunityId))
// Record disposable items as they are created so all can be disposed when needed.
using (DisposableCollection<SacsHierarchyItem> disposableItems = new DisposableCollection<SacsHierarchyItem>())
{
SaLogger.Warn(fn + " Failed to retrieve opportunity for Id: '" + model.OpportunityId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Validate the Organisation.
SysId organisationId = model.OpportunityOrganisationId.ToSysId();
if (!SysId.IsValid(organisationId))
{
SaLogger.Warn(fn + " Organisation Id not specified for Opportunity.");
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
if (organisation == null || !organisation.IsStatusActive)
{
SaLogger.Warn(fn + " " + (organisation == null ? "Invalid" : "Inactive") + " organisation for Opportunity. OrganisationId: '" + model.OpportunityOrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (opportunity != null && !opportunity.OrganisationId.Equals(organisationId))
{
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for Opportunity. Expected: " + opportunity.OrganisationId + ". Found: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Ensure that the user has the correct role to update Opportunities for this organisation.
if (!AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisationId, Sax.OrganisationRole.OpportunityAdmin))
{
SaLogger.Warn(fn + " User doesn not have 'Opportunity Admin' role for Organisation Id: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Create new item if required.
if (opportunity == null)
opportunity = ActivityMgr.CreateOrganisationOpportunity(organisationId);
// Populate item properties.
if (model.OpportunityRegionId != null)
opportunity.RegionIdPrimary = model.OpportunityRegionId.ToSysId();
if (model.OpportunitySportId != null)
opportunity.SportIdPrimary = model.OpportunitySportId.ToSysId();
if (model.OpportunityTypeCode != null)
opportunity.OpportunityType = (Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(model.OpportunityTypeCode);
if (model.OpportunityPosition != null)
opportunity.Position = model.OpportunityPosition;
if (model.OpportunityOutline != null)
opportunity.Outline = model.OpportunityOutline;
if (model.OpportunityStatusCode != null)
opportunity.Status = model.OpportunityStatus;
// Store item.
if (!SysId.IsValid(opportunity.Id))
{
if (!ActivityMgr.InsertOrganisationOpportunity(opportunity, DbUpdateInfo))
// Retrieve existing item.
SaxOrganisationOpportunity opportunity = ActivityMgr.GetOrganisationOpportunityById(opportunityId);
disposableItems.Add(opportunity);
if (opportunity == null && SysId.IsValid(opportunityId))
{
SaLogger.Warn(fn + " Failed to insert opportunity: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + ActivityMgr.ErrorStateMessage));
SaLogger.Warn(fn + " Failed to retrieve opportunity for Id: '" + model.OpportunityId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
}
else
{
if (!ActivityMgr.UpdateOrganisationOpportunity(opportunity, DbUpdateInfo))
// Validate the Organisation.
SysId organisationId = model.OpportunityOrganisationId.ToSysId();
if (!SysId.IsValid(organisationId))
{
SaLogger.Warn(fn + " Failed to update opportunity [Id:" + SysId.ToString(opportunity.Id) + "]: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + ActivityMgr.ErrorStateMessage));
SaLogger.Warn(fn + " Organisation Id not specified for Opportunity.");
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 Opportunity. OrganisationId: '" + model.OpportunityOrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (opportunity != null && !opportunity.OrganisationId.Equals(organisationId))
{
SaLogger.Warn(fn + " Inconsistent Organisation Id specified for Opportunity. Expected: " + opportunity.OrganisationId + ". Found: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Ensure that the user has the correct role to update Opportunities for this organisation.
if (!AccountMgr.UserHasOrganisationRole(SessionData.User.UserAccountId, organisationId, Sax.OrganisationRole.OpportunityAdmin))
{
SaLogger.Warn(fn + " User doesn't have 'Opportunity Admin' role for Organisation Id: " + organisationId);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Create new item if required.
if (opportunity == null)
{
opportunity = ActivityMgr.CreateOrganisationOpportunity(organisationId);
disposableItems.Add(opportunity);
}
// Populate item properties.
if (model.OpportunityRegionId != null)
opportunity.RegionIdPrimary = model.OpportunityRegionId.ToSysId();
if (model.OpportunitySportId != null)
opportunity.SportIdPrimary = model.OpportunitySportId.ToSysId();
if (model.OpportunityTypeCode != null)
opportunity.OpportunityType = (Sax.OpportunityType)OpportunityTypeCodes.GetTypeForCode(model.OpportunityTypeCode);
if (model.OpportunityPosition != null)
opportunity.Position = model.OpportunityPosition;
if (model.OpportunityOutline != null)
opportunity.Outline = model.OpportunityOutline;
if (model.OpportunityStatusCode != null)
opportunity.Status = model.OpportunityStatus;
// Store item.
if (!SysId.IsValid(opportunity.Id))
{
if (!ActivityMgr.InsertOrganisationOpportunity(opportunity, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert opportunity: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"]));
}
}
else
{
if (!ActivityMgr.UpdateOrganisationOpportunity(opportunity, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update opportunity [Id:" + SysId.ToString(opportunity.Id) + "]: " + ActivityMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"]));
}
}
// Store Opportunity Activity Index data.
ActivityConsole.StoreActivityIndex(opportunity, DbUpdateInfo);
// Construct response.
PopulateOpportunityResponseData(model, opportunity, responseData.Opportunity);
}
// Store Opportunity Activity Index data.
ActivityConsole.StoreActivityIndex(opportunity, DbUpdateInfo);
// Construct response.
PopulateOpportunityResponseData(model, opportunity, responseData.Opportunity);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
@@ -0,0 +1,190 @@
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.Utils;
using Saxonite.Net.Core.Web.Online.App;
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 - Request - Ajax actions.
//=======================================================================
partial class OrganisationController
{
//-------------------------------------------------------------------
// Request Organisation ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_RequestOrganisation : AjaxResponse_Data
{
// Construction.
public AjaxResponse_RequestOrganisation(SaxModel_Online model) : base(model) { }
// Organisation list.
public List<OrganisationResponseData> Organisations { get; } = new List<OrganisationResponseData>();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Organisation/Ajax/Request")]
[Route("Organisation/Ajax/Register")]
public IActionResult Ajax_RequestOrganisation(Model_Organisation model)
{
String fn = GetType().Name + ".Ajax_RequestOrganisation";
String messageTitle = Localiser["organisation.caption.organisation.request"];
AjaxResponse_RequestOrganisation responseData = new AjaxResponse_RequestOrganisation(model);
// Validate session and referrer. User does not need to be logged in.
if (!ValidReferer)
return Forbid();
SaxSessionData_Online sessionData = SessionData_Online;
if (!model.ValidateOrganisationRequestData(responseData))
return Json(responseData);
// Check Regions.
SaxRegion regionCountry = Internals.GetRegion(model.OrganisationRegionIdCountry.ToSysId());
if (SysId.IsValid(model.OrganisationRegionIdCountry.ToSysId()) && regionCountry == null)
{
SaLogger.Warn(fn + " Country region not found. Id: " + model.OrganisationRegionIdCountry + ". " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
SaxRegion regionProvince = Internals.GetRegion(model.OrganisationAddressRegionIdProvince.ToSysId());
if (SysId.IsValid(model.OrganisationAddressRegionIdProvince.ToSysId()) && regionProvince == null)
{
SaLogger.Warn(fn + " Province region not found. Id: " + model.OrganisationAddressRegionIdProvince + ". " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// User does not need to be logged in, but user details must be supplied if not.
SaxUserAccount userAccount = null;
if (ValidUserSession)
{
// Check that an email address hasn't been supplied.
// NB Shouldn't happen as contact controls aren't displayed if user is logged in,
// hence 'System' error response and nothing more specific.
if (!StringUtil.IsEmpty(model.ContactEmailAddress))
{
SaLogger.Warn(fn + " Contact Email supplied when user logged in. " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve user account.
userAccount = AccountMgr.GetUserAccountById(sessionData.User.UserAccountId);
if (userAccount == null)
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
else
{
// Double check that contact details have been supplied - validated by model above.
if (StringUtil.IsEmpty(model.ContactEmailAddress) || StringUtil.IsEmpty(model.ContactFirstName) || StringUtil.IsEmpty(model.ContactLastName))
{
SaLogger.Warn(fn + " Incomplete contact details supplied.");
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Check that the email doesn't exist.
// NB This is validated by the model and shouldn't be required here.
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.ContactEmailAddress);
if (userAccount != null)
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
userAccount = AccountMgr.CreateUserAccount();
userAccount.EmailAddress = model.ContactEmailAddress;
userAccount.FirstName = model.ContactFirstName;
userAccount.LastName = model.ContactLastName;
if (!AccountMgr.InsertUserAccount(userAccount, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert user contact - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
if (SysId.IsValid(model.OrganisationSportId.ToSysId()))
{
// Add User Sport if not already present.
// NB This will also reactivate an inactive or deleted User Sport.
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
prmUserSport.UserAccountIdsIncluded.Add(userAccount.Id);
prmUserSport.SportIdsIncluded.Add(model.OrganisationSportId.ToSysId());
prmUserSport.StatusCat = SaxUserSport.StatusCat.Any;
SaxUserSport userSport = AccountMgr.GetUserSport(prmUserSport);
if (userSport == null)
userSport = AccountMgr.CreateUserSport(userAccount.Id, model.OrganisationSportId.ToSysId());
userSport.Status = SaxUserSport.DefaultStatus;
if (!SysId.IsValid(userSport.Id))
{
if (!AccountMgr.InsertUserSport(userSport, DbUpdateInfo))
{
// Logg error but don't abort the request.
SaLogger.Warn(fn + " Failed to insert User Sport: " + AccountMgr.ErrorStateMessage);
}
}
else
{
if (!AccountMgr.UpdateUserSport(userSport, DbUpdateInfo))
{
// Logg error but don't abort the request.
SaLogger.Warn(fn + " Failed to update User Sport: " + AccountMgr.ErrorStateMessage);
}
}
}
// Create Organisation.
SaxOrganisation organisation = AccountMgr.CreateOrganisation();
organisation.Name = model.OrganisationName;
organisation.OrganisationType = model.GetOrganisationType();
organisation.OrganisationCategory = model.GetOrganisationCategory();
organisation.SportIdPrimary = model.OrganisationSportId.ToSysId();
organisation.RegionIdPrimary = model.OrganisationRegionIdCountry.ToSysId();
organisation.PhoneMain = model.OrganisationPhoneMain;
organisation.Status = SaStatus.Awaiting;
if (!AccountMgr.InsertOrganisation(organisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert organisation - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Add user as member of organisation.
SaxUserOrganisation userOrganisation = AccountMgr.CreateUserOrganisation(userAccount.Id, organisation.Id);
userOrganisation.OrganisationRoles = new List<Sax.OrganisationRole>() { Sax.OrganisationRole.Member, Sax.OrganisationRole.MemberAdmin };
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert user organisation - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Create Organisation address.
SaxItemAddress organisationAddress = ItemDataMgr.CreateItemAddress(organisation.GetItemId(), Sax.AddressType.Office);
organisationAddress.Line1 = model.OrganisationAddressLine1;
organisationAddress.Line2 = model.OrganisationAddressLine2;
organisationAddress.Line3 = model.OrganisationAddressLine3;
organisationAddress.Town = model.OrganisationAddressTown;
organisationAddress.Province = model.OrganisationAddressProvince;
organisationAddress.RegionIdProvince = model.OrganisationAddressRegionIdProvince.ToSysId();
if (SysId.IsValid(regionCountry.Id))
{
organisationAddress.Country = regionCountry.Name;
organisationAddress.RegionIdCountry = regionCountry.Id;
}
else organisationAddress.Country = model.OrganisationAddressCountry;
organisationAddress.PostalCode = model.OrganisationAddressPostalCode;
if (!ItemDataMgr.InsertItemAddress(organisationAddress, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert organisation address - " + ItemDataMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Complete response.
responseData.SetMessage(messageTitle, Localiser["msg.organisation.request.success"].ToString().ReplaceAll("\n", "<br>"));
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -106,169 +106,6 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
return Json(responseData);
}
//-------------------------------------------------------------------
// Request Organisation ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_RequestOrganisation : AjaxResponse_Data
{
// Construction.
public AjaxResponse_RequestOrganisation(SaxModel_Online model) : base(model) { }
// Organisation list.
public List<OrganisationResponseData> Organisations { get; } = new List<OrganisationResponseData>();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Organisation/Ajax/RequestOrganisation")]
public IActionResult Ajax_RequestOrganisation(Model_Organisation model)
{
String fn = GetType().Name + ".Ajax_RequestOrganisation";
String messageTitle = Localiser["organisation.caption.organisation.request"];
AjaxResponse_RequestOrganisation responseData = new AjaxResponse_RequestOrganisation(model);
// Validate session and referrer. User does not need to be logged in.
if (!ValidReferer)
return Forbid();
SaxSessionData_Online sessionData = SessionData_Online;
if (!model.ValidateOrganisationRequestData(responseData))
return Json(responseData);
// Check Regions.
SaxRegion regionCountry = Internals.GetRegion(model.OrganisationRegionIdCountry.ToSysId());
if (SysId.IsValid(model.OrganisationRegionIdCountry.ToSysId()) && regionCountry == null)
{
SaLogger.Warn(fn + " Country region not found. Id: " + model.OrganisationRegionIdCountry + ". " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
SaxRegion regionProvince = Internals.GetRegion(model.OrganisationAddressRegionIdProvince.ToSysId());
if (SysId.IsValid(model.OrganisationAddressRegionIdProvince.ToSysId()) && regionProvince == null)
{
SaLogger.Warn(fn + " Province region not found. Id: " + model.OrganisationAddressRegionIdProvince + ". " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// User does not need to be logged in, but user details must be supplied if not.
SaxUserAccount userAccount = null;
if (ValidUserSession)
{
// Check that an email address hasn't been supplied.
// NB Shouldn't happen as contact controls aren't displayed if user is logged in,
// hence 'System' error response and nothing more specific.
if (!StringUtil.IsEmpty(model.ContactEmailAddress))
{
SaLogger.Warn(fn + " Contact Email supplied when user logged in. " + getLogSuffix());
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Retrieve user account.
userAccount = AccountMgr.GetUserAccountById(sessionData.User.UserAccountId);
if (userAccount == null)
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
else
{
// Double check that contact details have been supplied - validated by model above.
if (StringUtil.IsEmpty(model.ContactEmailAddress) || StringUtil.IsEmpty(model.ContactFirstName) || StringUtil.IsEmpty(model.ContactLastName))
{
SaLogger.Warn(fn + " Incomplete contact details supplied.");
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Check that the email doesn't exist.
// NB This is validated by the model and shouldn't be required here.
userAccount = AccountMgr.GetUserAccountByEmailAddress(model.ContactEmailAddress);
if (userAccount != null)
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
userAccount = AccountMgr.CreateUserAccount();
userAccount.EmailAddress = model.ContactEmailAddress;
userAccount.FirstName = model.ContactFirstName;
userAccount.LastName = model.ContactLastName;
if (!AccountMgr.InsertUserAccount(userAccount, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert user contact - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
}
if (SysId.IsValid(model.OrganisationSportId.ToSysId()))
{
// Add User Sport if not already present.
// NB This will also reactivate an inactive or deleted User Sport.
SaxUserSport.Params prmUserSport = new SaxUserSport.Params();
prmUserSport.UserAccountIdsIncluded.Add(userAccount.Id);
prmUserSport.SportIdsIncluded.Add(model.OrganisationSportId.ToSysId());
prmUserSport.StatusCat = SaxUserSport.StatusCat.Any;
SaxUserSport userSport = AccountMgr.GetUserSport(prmUserSport);
if (userSport == null)
userSport = AccountMgr.CreateUserSport(userAccount.Id, model.OrganisationSportId.ToSysId());
userSport.Status = SaxUserSport.DefaultStatus;
if (!SysId.IsValid(userSport.Id))
{
if (!AccountMgr.InsertUserSport(userSport, DbUpdateInfo))
{
// Logg error but don't abort the request.
SaLogger.Warn(fn + " Failed to insert User Sport: " + AccountMgr.ErrorStateMessage);
}
}
else
{
if (!AccountMgr.UpdateUserSport(userSport, DbUpdateInfo))
{
// Logg error but don't abort the request.
SaLogger.Warn(fn + " Failed to update User Sport: " + AccountMgr.ErrorStateMessage);
}
}
}
// Create Organisation.
SaxOrganisation organisation = AccountMgr.CreateOrganisation();
organisation.Name = model.OrganisationName;
organisation.OrganisationType = model.GetOrganisationType();
organisation.OrganisationCategory = model.GetOrganisationCategory();
organisation.SportIdPrimary = model.OrganisationSportId.ToSysId();
organisation.RegionIdPrimary = model.OrganisationRegionIdCountry.ToSysId();
organisation.PhoneMain = model.OrganisationPhoneMain;
organisation.Status = SaStatus.Awaiting;
if (!AccountMgr.InsertOrganisation(organisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert organisation - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Add user as member of organisation.
SaxUserOrganisation userOrganisation = AccountMgr.CreateUserOrganisation(userAccount.Id, organisation.Id);
userOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.Member);
if (!AccountMgr.InsertUserOrganisation(userOrganisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert user organisation - " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Create Organisation address.
SaxItemAddress organisationAddress = ItemDataMgr.CreateItemAddress(organisation.GetItemId(), Sax.AddressType.Office);
organisationAddress.Line1 = model.OrganisationAddressLine1;
organisationAddress.Line2 = model.OrganisationAddressLine2;
organisationAddress.Line3 = model.OrganisationAddressLine3;
organisationAddress.Town = model.OrganisationAddressTown;
organisationAddress.Province = model.OrganisationAddressProvince;
organisationAddress.RegionIdProvince = model.OrganisationAddressRegionIdProvince.ToSysId();
if (SysId.IsValid(regionCountry.Id))
{
organisationAddress.Country = regionCountry.Name;
organisationAddress.RegionIdCountry = regionCountry.Id;
}
else organisationAddress.Country = model.OrganisationAddressCountry;
organisationAddress.PostalCode = model.OrganisationAddressPostalCode;
if (!ItemDataMgr.InsertItemAddress(organisationAddress, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert organisation address - " + ItemDataMgr.ErrorStateMessage);
return Json(responseData.SetGoHome(messageTitle, Localiser["msg.error.system"]));
}
// Complete response.
responseData.SetMessage(messageTitle, Localiser["msg.organisation.request.success"].ToString().ReplaceAll("\n", "<br>"));
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Get Member Organisation List ajax request.
//-------------------------------------------------------------------
@@ -46,26 +46,80 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!ValidUserSession)
return RedirectToAction("", "");
// Model.
Model_Organisation_Opportunities model = new Model_Organisation_Opportunities(Localiser);
// Get a suitable organisation for the filter.
SysId filterOrganisationId = SessionData_Online.Filter.OrganisationIdMember;
String filterOrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
OrganisationData organisationData = GetOrganisationForFilter(filterOrganisationId, filterOrganisationCaption);
if (organisationData == null)
return RedirectToAction("", "");
// Make a note of the filter values.
model.Filter.OrganisationId = SysId.ToString(organisationData.Id);
model.Filter.OrganisationCaption = organisationData.Caption;
SessionData_Online.Filter.OrganisationIdMember = organisationData.Id;
SessionData_Online.Filter.OrganisationCaptionMember = organisationData.Caption;
return View(model);
}
//-------------------------------------------------------------------
[HttpGet]
public IActionResult Members()
{
// Validate session.
if (!ValidUserSession)
return RedirectToAction("", "");
// Model.
Model_Organisation_Members model = new Model_Organisation_Members(Localiser);
// Get a suitable organisation for the filter.
SysId filterOrganisationId = SessionData_Online.Filter.OrganisationIdMember;
String filterOrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
OrganisationData organisationData = GetOrganisationForFilter(filterOrganisationId, filterOrganisationCaption);
if (organisationData == null)
return RedirectToAction("", "");
// Make a note of the filter values.
model.Filter.OrganisationId = SysId.ToString(organisationData.Id);
model.Filter.OrganisationCaption = organisationData.Caption;
SessionData_Online.Filter.OrganisationIdMember = organisationData.Id;
SessionData_Online.Filter.OrganisationCaptionMember = organisationData.Caption;
return View(model);
}
//-------------------------------------------------------------------
public class OrganisationData
{
public OrganisationData(SysId id) { Id = id; }
public SysId Id { get; }
public String Caption { get; set; }
}
private OrganisationData GetOrganisationForFilter(SysId filterOrganisationId, String filterOrganisationCaption)
{
// Check that user is associated with organisations.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
if (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) < 1)
return RedirectToAction("", "");
// Model.
Model_Organisation_Opportunities model = new Model_Organisation_Opportunities(Localiser);
return null;
// Filter organisation.
model.Filter.OrganisationId = SysId.ToString(SessionData_Online.Filter.OrganisationIdMember);
model.Filter.OrganisationCaption = SessionData_Online.Filter.OrganisationCaptionMember;
if (StringUtil.IsEmpty(model.Filter.OrganisationId))
OrganisationData organisationData = new OrganisationData(filterOrganisationId);
organisationData.Caption = filterOrganisationCaption;
if (!SysId.IsValid(filterOrganisationId) || StringUtil.IsEmpty(filterOrganisationCaption))
{
// Pick the first Organisation that the user is a member of.
ColumnDfn colOrganisationId = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.OrganisationId);
ColumnDfn colOrganisationName = AccountMgr.GetUserOrganisationColumnDfn(SaxUserOrganisation.Column.Organisation_Name);
prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
if (SysId.IsValid(filterOrganisationId))
prmUserOrganisation.OrganisationIdsIncluded.Add(filterOrganisationId);
prmUserOrganisation.OrganisationMembersOnly = true;
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
prmUserOrganisation.SortColumns.Add(colOrganisationName);
@@ -76,29 +130,26 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
model.Filter.OrganisationId = SysId.ToString(new SysId(values.GetLong(colOrganisationId.DataName)));
if (!StringUtil.IsEmpty(model.Filter.OrganisationId))
SysId organisationId = new SysId(values.GetLong(colOrganisationId.DataName));
if (SysId.IsValid(organisationId))
{
model.Filter.OrganisationCaption = values.GetString(colOrganisationName.DataName);
organisationData = new OrganisationData(organisationId);
organisationData.Caption = values.GetString(colOrganisationName.DataName);
break;
}
}
}
}
if (SysId.IsValid(model.Filter.OrganisationId.ToSysId()) && StringUtil.IsEmpty(model.Filter.OrganisationCaption))
if (SysId.IsValid(organisationData.Id) && StringUtil.IsEmpty(organisationData.Caption))
{
// Organisation has been identified but no caption available as yet.
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(model.Filter.OrganisationId.ToSysId()))
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationData.Id))
{
if (organisation != null)
model.Filter.OrganisationCaption = organisation.Name;
organisationData.Caption = organisation.Name;
}
}
// Make a note of the filter values.
SessionData_Online.Filter.OrganisationIdMember = model.Filter.OrganisationId.ToSysId();
SessionData_Online.Filter.OrganisationCaptionMember = model.Filter.OrganisationCaption;
return View(model);
return organisationData;
}
//-------------------------------------------------------------------
@@ -60,18 +60,18 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (userAccount == null)
{
SaLogger.Error(fn + " Unable to sign account in - null user account.");
errorMessage = Localiser["security.msg.signin.failed"];
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (!userAccount.IsStatusActive)
{
SaLogger.Error(fn + " Unable to sign account in - user account is not active. Email: " + userAccount.EmailAddress);
errorMessage = Localiser["security.msg.signin.failed"];
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// 'Keep logged in' can be switched off by the application configuration.
keepLoggedIn = App.SessionConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
keepLoggedIn = App.AppConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
// Log user in.
userAccount.KeepLoggedIn_Online = keepLoggedIn;
@@ -81,7 +81,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update account for " + userAccount.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
errorMessage = Localiser["security.msg.signin.failed"];
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
SaLogger.Info(fn + " User session opened for " + userAccount.EmailAddress, true);
@@ -176,7 +176,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
protected void SetKeepLoggedInCookie()
{
String keepLoggedInCookieValue = GenerateKeepLoggedInCookieValue();
int cookieExpiresDays = Math.Max(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Min, Math.Min(Sax.Config.Security.SignIn.KeepLoggedIn.CookieExpiresDays_Max, SessionConfig.Security.SignIn.KeepLoggedIn.CookieExpiresDays));
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);
SaLogger.Info(this.GetType().Name + ".SetKeepLoggedInCookie 'Keep Logged In' cookie set. Value: " + keepLoggedInCookieValue);
}
@@ -86,7 +86,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
if (!ValidUserSession)
return Json(responseData.SetGoHome());
if (!SessionConfig.Security.SignIn.KeepLoggedIn.Allowed)
if (!AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
return Json(responseData);
// Resend the cookie to extend the expiry date if it is currently populated.
@@ -397,7 +397,7 @@ namespace Saxonite.Net.Core.Web.Online.Controllers
}
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Online controller)
{
int expiresMinutes = controller.SessionConfig.Security.SignIn.PasswordRequest.EmailLinkExpiresMins;
int expiresMinutes = controller.AppConfig.Security.SignIn.PasswordRequest.EmailLinkExpiresMins;
int expiresMinutes_Min = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Min;
int expiresMinutes_Max = Sax.Config.Security.SignIn.PasswordRequest.EmailLinkExpiresMins_Max;
return Math.Max(expiresMinutes_Min, Math.Min(expiresMinutes_Max, expiresMinutes));
@@ -0,0 +1,118 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Online.Models
{
//=======================================================================
public class Model_Organisation_Members : SaxModel_Online
{
//-------------------------------------------------------------------
// Construction.
public Model_Organisation_Members(SaxLocaliser localiser) :
base(localiser)
{
//AdditionalFiles_CSS.Add("css/sax-org-mbr.css");
AdditionalFiles_JS.Add("js/sax-org-mbr.js");
}
//-------------------------------------------------------------------
// List configuration.
public class MemberFilterData
{
public String OrganisationId { get; set; }
public String OrganisationCaption { get; set; }
public String Member { get; set; }
public String OrganisationRole { get; set; }
}
public MemberFilterData Filter { get; } = new MemberFilterData();
//-------------------------------------------------------------------
// Member properties.
public String MemberId { get; set; }
public String MemberExists { get; set; }
// Member properties.
public String MemberOrganisationId { get; set; }
public String MemberEmailAddress { get; set; }
public String MemberNameSupplied{ get; set; }
public String MemberTitle { get; set; }
public String MemberFirstName { get; set; }
public String MemberLastName { get; set; }
public String MemberRoleCodeDelim = ",";
public List<String> MemberRoleCodes { get; set; }
public List<String> GetMemberRoleCodes()
{
List<String> codes = new List<string>();
foreach (String code in MemberRoleCodes)
{
if (StringUtil.IsEmpty(code)) continue;
codes.AddRange(code.Split(MemberRoleCodeDelim));
}
return codes;
}
public String MemberAdminComment { get; set; }
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// Member.
public bool ValidateMemberData(SaxController_Base.AjaxResponse_Data responseData)
{
// Member Email Address.
if (MemberEmailAddress != null)
{
responseData.SetControlValue(nameof(MemberEmailAddress), MemberEmailAddress);
if (StringUtil.IsEmpty(MemberEmailAddress))
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(MemberEmailAddress) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress)]);
else if (!SacsDataValidationHelper.IsValidEmailAddress(MemberEmailAddress))
responseData.SetControlError(nameof(MemberEmailAddress), Localiser["msg.validation.invalid.value"]);
}
// Member First Name.
bool memberNameSupplied = StringUtil.ToBool(MemberNameSupplied);
if (MemberFirstName != null && memberNameSupplied)
{
responseData.SetControlValue(nameof(MemberFirstName), MemberFirstName);
if (StringUtil.IsEmpty(MemberFirstName))
responseData.SetControlError(nameof(MemberFirstName), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(MemberFirstName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))
responseData.SetControlError(nameof(MemberFirstName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName)]);
}
// Member Last Name.
if (MemberLastName != null && memberNameSupplied)
{
responseData.SetControlValue(nameof(MemberLastName), MemberLastName);
if (StringUtil.IsEmpty(MemberLastName))
responseData.SetControlError(nameof(MemberLastName), Localiser["msg.validation.mandatory.value"]);
else if (StringUtil.GetLength(MemberLastName) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))
responseData.SetControlError(nameof(MemberLastName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName)]);
}
// Member Admin Comment.
if (MemberAdminComment != null)
{
responseData.SetControlValue(nameof(MemberAdminComment), MemberAdminComment);
if (!StringUtil.IsEmpty(MemberAdminComment) && StringUtil.GetLength(MemberAdminComment) > GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment))
responseData.SetControlError(nameof(MemberAdminComment), Localiser["msg.validation.maximum.length", GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment)]);
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -16,6 +16,8 @@ namespace Saxonite.Net.Core.Web.Online.Models
{
//-------------------------------------------------------------------
// Data members.
private bool userCanManageOrganisationMembers = false;
private bool userCanManageOrganisationMembersChecked = false;
private bool userCanManageOrganisationOpportunities = false;
private bool userCanManageOrganisationOpportunitiesChecked = false;
@@ -31,6 +33,23 @@ namespace Saxonite.Net.Core.Web.Online.Models
public SaxSessionData_Online SessionData_Online { get { return SessionData as SaxSessionData_Online; } }
// Security profile.
public bool UserIsJournalist { get { return SessionData != null && SessionData.User != null && SessionData.User.IsJournalist; } }
public bool UserCanManageOrganisationMembers
{
get
{
if (!userCanManageOrganisationMembersChecked && ValidUserSession)
{
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.UserAccountIdsIncluded.Add(SessionData.User.UserAccountId);
prmUserOrganisation.OrganisationMembersOnly = true;
prmUserOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.OpportunityAdmin);
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
userCanManageOrganisationMembers = (AccountMgr.GetUserOrganisationCount(prmUserOrganisation) > 0);
userCanManageOrganisationMembersChecked = true;
}
return userCanManageOrganisationMembers;
}
}
public bool UserCanManageOrganisationOpportunities
{
get
@@ -28,21 +28,11 @@
</ItemGroup>
<ItemGroup>
<Content Update="appsettings.Machine.Sarand106.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.Machine.Sarand107.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Update="appsettings.Machine.Sarand602.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
@@ -9,7 +9,22 @@
<div class="row">
<div class="col"><div class="sax-caption">@Localiser["account.caption.profile.contact"]</div></div>
<div class="fixed">
<div class="sax-action sax-edit"><img src="~/img/action/edit24.png" alt="@(Localiser["label.update"])" title="@(Localiser["label.update"])" /></div>
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
<li class="sax-dropdown-item sax-action sax-edit"><div class="sax-label">@(Localiser["label.update"])</div></li>
</ul>
</li>
</ul>
@* Filter item templates *@
<div class="sax-panel-item-template">
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu ProfileContact">
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
</ul>
</div>
</div>
</div>
</div>
@@ -130,7 +145,7 @@
<div class="sax-control row">
@Html.HiddenFor(model => model.AccountRegionIdCountry, new { @id = "ifAccountRegionIdCountry", @class = "AccountRegionIdCountry" })
<div class="col"><input type="text" id="ifAccountRegionCaptionCountry" class="AccountRegionCaptionCountry sax-input" readonly="readonly" onDblClick="sax.selectRegionCountry()" /></div>
<div class="fixed"><button id="pbSelectRegionCountry" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegionCountry()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectRegionCountry sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegionCountry()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -33,8 +33,12 @@
</div>
<div class="sax-content">
<div class="row">
<div class="col-sm-6"><div class=""></div></div>
<div class="col-sm-6"><div class=""></div></div>
<div class="col-sm-6"><div class="OrganisationSport sax-note"></div></div>
<div class="col-sm-6 text-sm-right"><div class="OrganisationRegion sax-note"></div></div>
</div>
<div class="row">
<div class="col-sm-6"><div class="OrganisationMemberCount sax-note sa-action">@Localiser["label.members"]:&nbsp;<span class="MemberCount"></span></div></div>
<div class="col-sm-6 text-sm-right"><div class="OrganisationOpportunityCount sax-note sa-action">@Localiser["label.opportunities"]:&nbsp;<span class="OpportunityCount"></span></div></div>
</div>
</div>
</div>
@@ -9,7 +9,22 @@
<div class="row">
<div class="col"><div class="sax-caption">@Localiser["account.caption.profile.sports"]</div></div>
<div class="fixed">
<div class="sax-action sax-add"><img src="~/img/action/add24.png" alt="@(Localiser["label.add"])" title="@(Localiser["label.add"])" /></div>
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
<li class="sax-dropdown-item sax-action sax-add"><div class="sax-label">@(Localiser["label.add"])</div></li>
</ul>
</li>
</ul>
@* Filter item templates *@
<div class="sax-panel-item-template">
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu ProfileSports">
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
</ul>
</div>
</div>
</div>
</div>
@@ -24,7 +39,15 @@
<div class="sax-header row">
<div class="col"><div class="SportName"></div></div>
<div class="fixed">
<div class="sax-action sax-edit"><img src="~/img/action/edit24.png" alt="@(Localiser["label.update"])" title="@(Localiser["label.update"])" /></div>
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">
<li class="sax-dropdown-item sax-action sax-edit"><div class="sax-label">@(Localiser["label.update"])</div></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="sax-content">
@@ -58,7 +81,7 @@
<div class="sax-control row">
<input type="hidden" id="ifProfileSportId" class="ProfileSportId" name="ProfileSportId" />
<div class="col"><input type="text" id="ifProfileSport" class="ProfileSport sax-input" name="ProfileSport" readonly="readonly" maxlength=128 /></div>
<div class="fixed"><button id="pbSelectSport" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectUserSport()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectUserSport()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -34,7 +34,9 @@
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
</script>
<partial name="~/Views/Common/RegionSelect.cshtml" />
<partial name="~/Views/Common/SportSelect.cshtml" />
</div>
@@ -0,0 +1,56 @@
@model SaxModel_Online
@inject SaxLocaliser Localiser
<link rel="stylesheet" href="~/css/sax-code-sel.css?@Model.HrefVersion" />
<script src="~/js/sax-code-sel.js?@Model.HrefVersion"></script>
<script type="text/javascript">
</script>
<div id="dlgCodeSelect" class="sax-dialog sax-form" style="padding-bottom:8px;">
@* Filter *@
<div class=""></div>
<div class="row h-100">
@* Available codes *@
<div class="col-sm-5">
<div class="h-100 sax-codeSelect-codes AvailableCodes"></div>
</div>
@* Code selection *@
<div class="col-sm-2">
<div class="row">
<div class="col-sx-6 col-sm-12 center">
<button class="sax-button Select">@Localiser["label.select"]</button>
</div>
<div class="col-sx-6 col-sm-12 center">
<button class="sax-button Remove">@Localiser["label.remove"]</button>
</div>
</div>
</div>
@* Selected codes *@
<div class="col-sm-5">
<div class="h-100 sax-codeSelect-codes SelectedCodes">
</div>
</div>
</div>
<div class="sax-panel-item-template">
<div class="sax-panel-item Code">
<div class="CodeDesc"></div>
</div>
</div>
</div>
@@ -75,7 +75,7 @@
<div class="sax-form-control">
<div class="sax-caption">
<label for="ifContactEmailAddress"><span>@Localiser["label.organsiation.details"]</span></label>
<label for=""><span>@Localiser["label.organsiation.details"]</span></label>
</div>
</div>
@@ -132,7 +132,7 @@
<div class="sax-control row">
<input type="hidden" id="ifOrganisationSportId" name="OrganisationSportId" OrganisationSportId"" class="OrganisationSportId" />
<div class="col"><input type="text" id="ifOrganisationSportCaption" class="OrganisationSportCaption sax-input" readonly="readonly" ondblclick="sax.selectSport()" /> </div>
<div class="fixed"><button id="pbSelectSport" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectOrgSport()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectOrgSport()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -145,7 +145,7 @@
<div class="sax-control row">
<input type="hidden" id="ifOrganisationRegionIdCountry" name="OrganisationRegionIdCountry" OrganisationRegionIdCountry"" class="OrganisationRegionIdCountry" />
<div class="col"><input type="text" id="ifOrganisationRegionCaptionCountry" class="OrganisationRegionCaptionCountry sax-input" readonly="readonly" ondblclick="sax.selectRegion()" /> </div>
<div class="fixed"><button id="pbSelectRegion" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectOrgRegion()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectOrgRegion()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -55,7 +55,7 @@
<div class="sax-control row">
@Html.HiddenFor(model => model.ArticleSportId, new { @id = "ifArticleSportId", @class = "ArticleSportId" })
<div class="col">@Html.TextBoxFor(model => model.ArticleSportCaption, new { @id = "ifArticleSportCaption", @class = "ArticleSportCaption sax-input", @readonly = "readonly", @onDblClick = "sax.selectSport()" }) </div>
<div class="fixed"><button id="pbSelectSport" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectSport()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectSport()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -68,7 +68,7 @@
<div class="sax-control row">
@Html.HiddenFor(model => model.ArticleRegionId, new { @id = "ifArticleRegionId", @class = "ArticleRegionId" })
<div class="col">@Html.TextBoxFor(model => model.ArticleRegionCaption, new { @id = "ifArticleRegionCaption", @class = "ArticleRegionCaption sax-input", @readonly = "readonly", @onDblClick = "sax.selectRegion()" }) </div>
<div class="fixed"><button id="pbSelectRegion" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegion()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegion()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -0,0 +1,115 @@
@model Model_Organisation_Members
@inject SaxLocaliser Localiser
@{
ViewData["Title"] = "Organisation - Members";
}
<div id="pnlMembers" class="sax-panel">
<script type="text/javascript">
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
sax.lbl.remove = '@(Localiser.GetJavascriptText("label.remove"))';
sax.lbl.activate = '@(Localiser.GetJavascriptText("label.activate"))';
sax.msg.activate = '@(Localiser.GetJavascriptText("account.activate.info"))';
sax.dlg.title.remove = '@(Localiser.GetJavascriptText("organisation.member.remove"))';
sax.dlg.title.selectRoles = '@(Localiser.GetJavascriptText("organisation.member.select.roles"))';
sax.msg.remove= '@(Localiser.GetJavascriptText("organisation.member.remove.confirm"))';
sax.dlg.title.activate = '@(Localiser.GetJavascriptText("account.activate.caption"))';
</script>
@* Filter panel *@
<div class="sax-panel-filter">
@* Filter header *@
<div class="sax-header row">
@* Filter caption *@
<div class="col"><div class="sax-caption">@Localiser["organisation.members"]</div></div>
<div class="fixed row">
@* Burger menu *@
<ul class="nav navbar-nav navbar-dark navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
@* Filter item templates *@
<div class="sax-panel-item-template">
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu Members">
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
</ul>
</div>
</div>
</div>
<div class="sax-content">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMemberFilter", @class = "sax-form", @action = "#", @method = "POST", onsubmit = "return false;" }))
{
<div class="sax-control row">
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.organisation"]</div></div>
<div class="col-sm-8 row">
@Html.HiddenFor(model => model.Filter.OrganisationId, new { @id = "ifFilterOrganisationId", @class = "FilterOrganisationId" })
<div class="col"><input type="text" id="ifFilterOrganisation" class="FilterOrganisation sax-input" value="@(Model.Filter.OrganisationCaption)" /></div>
<div class="fixed"><button class="sax-button" onclick="sax.selectFilterOrganisation()">@Localiser["label.select"]</button></div>
</div>
</div>
<div class="sax-control row">
<div class="col-sm-4"><div class="sax-label text-left text-sm-right">@Localiser["label.search"]</div></div>
<div class="col-sm-8"><input type="search" id="ifMemberFilter" name="Filter.Member" class="MemberFilter sax-input" maxlength="64" autocomplete="off" /></div>
</div>
}
</div>
</div>
@* Results Panel *@
<div class="sax-panel-results">
<div class="sax-panel-messages"></div>
<div class="sax-panel-item-list"></div>
@* element templates *@
<div class="sax-panel-item-template">
@* Member item template *@
<div class="sax-panel-item Member">
<div class="sax-header row">
<div class="col">
@* Member caption *@
<div class="sax-caption"><div class="sax-action"><span class="MemberDisplayName"></span></div></div>
</div>
<div class="fixed sax-actions">
@* Burger menu *@
<ul class="nav navbar-nav navbar-light navbar-right sax-burger">
<li class="dropdown-toggle caret-off">
<a href="#" class="dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><span class="navbar-toggler-icon"></span></a>
<ul class="dropdown-menu dropdown-menu-right sax-dropdown-menu">@* Menu items will be inserted here. *@</ul>
</li>
</ul>
</div>
</div>
<div class="sax-content">
<div class="row">
<div class="col-sm-6"><div class="MemberEmail"></div></div>
<div class="col-sm-6 text-sm-right"><div class=""></div></div>
</div>
<div class="">
<div class="MemberAdminComment sax-note"></div>
</div>
<div class="row">
<div class="col-sm-6"><div class=" sax-note"></div></div>
<div class="col-sm-6 text-sm-right"><div class="MemberStatus sax-note"></div></div>
</div>
</div>
</div>
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu Member">
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
</ul>
</div>
</div>
</div>
<partial name="Panel-MemberDialog.cshtml" />
<partial name="~/Views/Common/OrganisationSelect.cshtml" />
<partial name="~/Views/Common/CodeSelect.cshtml" />
@@ -0,0 +1,119 @@
@model Model_Organisation_Members
@inject SaxLocaliser Localiser
@{
/* Organisation Members - Member dialog panel */
}
<script type="text/javascript">
sax.dlg.title.createMember = '@Localiser.GetJavascriptText("organisation.caption.member.create")';
sax.dlg.title.updateMember = '@Localiser.GetJavascriptText("organisation.caption.member.update")';
sax.dlg.title.selectRegion = '@Localiser.GetJavascriptText("reference.caption.region.select")';
sax.dlg.title.selectSport = '@Localiser.GetJavascriptText("reference.caption.sport.select")';
sax.data.userRoleCodeDelim = '@Model.MemberRoleCodeDelim';
</script>
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMemberId", @class = "sax-form" }))
{
<input type="hidden" name="MemberId" class="MemberId" />
}
<div id="dlgMember" class="sax-dialog" title="">
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmMember", @class = "sax-form", @onSubmit = "return false;" }))
{
<input type="hidden" name="MemberId" class="MemberId" />
<input type="hidden" name="MemberExists" class="MemberExists" />
<input type="hidden" name="MemberNameSupplied" class="MemberNameSupplied" />
<input type="hidden" class="MemberOrganisationId" name="MemberOrganisationId" value="@(Model.Filter.OrganisationId)" />
@* Member Email Address *@
<div class="sax-form-control MemberEmailAddress">
<div class="sax-label">
<label for="ifMemberEmailAddress"><span><span class="required">*</span> @Localiser["label.email"]</span></label>
</div>
<div class="sax-control">
<input type="text" name="MemberEmailAddress" class="MemberEmailAddress sax-input" autocomplete="off" readonly="readonly" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_EmailAddress))" />
</div>
<div class="sax-message"></div>
</div>
@* Member Display Name *@
<div class="sax-form-control MemberDisplayName">
<div class="sax-label">
<label for="ifMemberDisplayName"><span>@Localiser["label.name"]</span></label>
</div>
<div class="sax-control">
<input type="text" if="ifMemberDisplayName" class="MemberDisplayName sax-input" readonly="readonly" />
</div>
<div class="sax-message"></div>
</div>
@* Member Name *@
<div class="row">
<div class="col-sm-4">
@* User Title *@
<div class="sax-form-control MemberTitle">
<div class="sax-label">
<label for="cbMemberTitle"><span><span class="required">*</span> @Localiser["label.title"]</span></label>
</div>
<div class="sax-control">
<select id="cbMemberTitle" name="MemberTitle" class="MemberTitle sax-input"></select>
</div>
<div class="sax-message"></div>
</div>
</div>
<div class="col-sm-4">
@* User First Name *@
<div class="sax-form-control MemberFirstName">
<div class="sax-label">
<label for="ifMemberFirstName"><span><span class="required">*</span> @Localiser["label.first.name"]</span></label>
</div>
<div class="sax-control">
<input type="text" id="ifMemberFirstName" name="MemberFirstName" class="MemberFirstName sax-input" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_FirstName))" />
</div>
<div class="sax-message"></div>
</div>
</div>
<div class="col-sm-4">
@* User Last Name *@
<div class="sax-form-control MemberLastName">
<div class="sax-label">
<label for="ifMemberLastName"><span><span class="required">*</span> @Localiser["label.last.name"]</span></label>
</div>
<div class="sax-control">
<input type="text" id="ifMemberLastName" name="MemberLastName" class="MemberLastName sax-input" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserAccount_LastName))" />
</div>
<div class="sax-message"></div>
</div>
</div>
</div>
@* Member roles *@
<div class="sax-form-control MemberRoleCodes">
<div class="sax-label">
<label for="ifMemberRoles"><span>@Localiser["label.roles"]</span></label>
</div>
<div class="sax-control row">
<input type="hidden" name="MemberRoleCodes" class="MemberRoleCodes sax-input" />
<div class="col"><textarea class="MemberRoles sax-input" rows="6" readonly="readonly" ondblclick="sax.selectMemberRoles()"></textarea></div>
<div class="fixed"><button class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectMemberRoles()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@* Admin Comment *@
<div class="sax-form-control MemberAdminComment">
<div class="sax-label">
<label for="ifMemberAdminComment"><span>@Localiser["label.comment"]</span></label>
</div>
<div class="sax-control">
<textarea type="text" id="ifMemberAdminComment" name="MemberAdminComment" class="MemberAdminComment sax-textarea" rows="4" autocomplete="off" maxlength="@(Model.GetControlMaxLength(SaxDbDfn_Core.ColumnIdx.UserOrganisation_AdminComment))"></textarea>
</div>
<div class="sax-message"></div>
</div>
}
</div>
@@ -1,7 +1,7 @@
@model Model_Organisation_Opportunities
@inject SaxLocaliser Localiser
@{
/* Opportunities - Opportunity dialog panel */
/* Organisation Opportunities - Opportunity dialog panel */
}
<script type="text/javascript">
@@ -25,7 +25,7 @@
@* Opportunity type *@
<div class="sax-form-control OpportunityTypeCode">
<div class="sax-label">
<label for="ifOpportunityType"><span><span class="required">*</span> @Localiser["label.type"]</span></label>
<label for="cbOpportunityType"><span><span class="required">*</span> @Localiser["label.type"]</span></label>
</div>
<div class="sax-control">
<select id="cbOpportunityType" class="OpportunityType sax-select" name="OpportunityTypeCode"></select>
@@ -58,12 +58,12 @@
@* Sport *@
<div class="sax-form-control OpportunitySportId">
<div class="sax-label">
<label for="ifOpportunitySportId"><span><span class="required">*</span> @Localiser["label.sport"]</span></label>
<label for="ifOpportunitySportCaption"><span><span class="required">*</span> @Localiser["label.sport"]</span></label>
</div>
<div class="sax-control row">
@Html.HiddenFor(model => model.OpportunitySportId, new { @id = "ifOpportunitySportId", @class = "OpportunitySportId" })
<div class="col"><input type="text" id="ifOpportunitySportCaption" class="OpportunitySportCaption sax-input" readonly="readonly" ondblclick="sax.selectSport()" /></div>
<div class="fixed"><button id="pbSelectSport" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectSport()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectSport sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectSport()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -71,12 +71,12 @@
@* Region *@
<div class="sax-form-control OpportunityRegionId">
<div class="sax-label">
<label for="ifOpportunityRegionId"><span><span class="required">*</span> @Localiser["label.region"]</span></label>
<label for="ifOpportunityRegionCaption"><span><span class="required">*</span> @Localiser["label.region"]</span></label>
</div>
<div class="sax-control row">
@Html.HiddenFor(model => model.OpportunityRegionId, new { @id = "ifOpportunityRegionId", @class = "OpportunityRegionId" })
<div class="col"><input type="text" id="ifOpportunityRegionCaption" class="OpportunityRegionCaption sax-input" readonly="readonly" ondblclick="sax.selectRegion()" /></div>
<div class="fixed"><button id="pbSelectRegion" class="sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegion()">@Localiser["label.select"]</button></div>
<div class="fixed"><button class="SelectRegion sax-button" style="min-width:auto;margin-left:4px;padding:4px 6px" onclick="sax.selectRegion()">@Localiser["label.select"]</button></div>
</div>
<div class="sax-message"></div>
</div>
@@ -19,7 +19,7 @@
{
/* Current password - required when setting password within user session. */
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control PasswordCurrent">
<div class="sax-label"><label for="ifPasswordCurrent"><span><span class="required">*</span> @Localiser["label.password.current"]</span></label></div>
<div class="sax-control">
@Html.PasswordFor(model => model.PasswordCurrent, new { @id = "ifPasswordCurrent", @class = "sax-input", @maxlength = Model.PasswordMaxLength })
@@ -34,7 +34,7 @@
}
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control Password">
<div class="sax-label"><label for="ifPassword"><span><span class="required">*</span> @Localiser["label.password"]</span></label></div>
<div class="sax-control">
@Html.PasswordFor(model => model.Password, new { @id = "ifPassword", @class = "sax-input", @maxlength = Model.PasswordMaxLength })
@@ -47,7 +47,7 @@
</div>
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control PasswordConfirm">
<div class="sax-label"><label for="ifPasswordConfirm"><span><span class="required">*</span> @Localiser["label.password.confirm"]</span></label></div>
<div class="sax-control">
@Html.PasswordFor(model => model.PasswordConfirm, new { @id = "ifPasswordConfirm", @class = "sax-input", @maxlength = Model.PasswordMaxLength })
@@ -15,7 +15,7 @@
{
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control EmailAddress">
<div class="sax-label">
<label for="ifEmailAddress"><span><span class="required">*</span> @Localiser["label.email.address"]</span></label>
</div>
@@ -16,7 +16,7 @@
{
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control EmailAddress">
<div class="sax-label">
<label for="ifEmailAddress"><span><span class="required">*</span> @Localiser["label.email.address"]</span></label>
</div>
@@ -27,7 +27,7 @@
</div>
<div class="spacer4"></div>
<div class="sax-form-control">
<div class="sax-form-control Password">
<div class="row">
<div class="col-6">
<div class="sax-label">
@@ -54,7 +54,7 @@
}
@* Scripts *@
<script>
<script>
var sax = sax || { page: {}, url: {}, links: {}, data: {}, form: {}, ajax: {}, msg: {}, lbl: {}, dlg: { title: {}, btn: {} }, $frm: {}, $dlg: {}, $pnl: {} };
sax.url.base = '@Model.RedirectLocation.Base';
sax.url.home = '@Model.RedirectLocation.Home';
@@ -62,7 +62,6 @@
sax.links.facebook = '@Model.Links.Facebook';
sax.links.linkedin = '@Model.Links.LinkedIn';
sax.form.calendarDateFormat = '@(Model.CalendarDateFormat)';
sax.lbl.calendar='@Localiser.GetJavascriptText("label.calendar")';
sax.dlg.title.alert = '@Localiser.GetJavascriptText("dialog.title.alert")';
sax.dlg.title.confirm = '@Localiser.GetJavascriptText("dialog.title.confirm")';
sax.dlg.title.progress = '@Localiser.GetJavascriptText("dialog.title.progress")';
@@ -72,6 +71,10 @@
sax.dlg.btn.ok = '@Localiser["label.ok"]';
sax.dlg.btn.close = '@Localiser["label.close"]';
sax.dlg.btn.cancel = '@Localiser["label.cancel"]';
sax.lbl.refresh='@Localiser.GetJavascriptText("label.refresh")';
sax.lbl.create='@Localiser.GetJavascriptText("label.create")';
sax.lbl.add='@Localiser.GetJavascriptText("label.add")';
sax.lbl.calendar='@Localiser.GetJavascriptText("label.calendar")';
sax.lbl.availableCharacter = '@Localiser.GetJavascriptText("label.characters.one")';
sax.lbl.availableCharacters = '@Localiser.GetJavascriptText("label.characters.count", "{0}")';
sax.lbl.noneSelected = '@Localiser.GetJavascriptText("label.selected.none")';
@@ -88,7 +91,7 @@
sax.keepLoggedIn = @keepLoggedIn;
sax.keepLoggedInDelay = @(Sax.Config.Admin.Session.Cookie.KeepLoggedInTimeoutMillis);
sax.debugMode = @debug;
</script>
</script>
</head>
<body>
@@ -130,6 +133,10 @@
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Journalist/Articles');">@Localiser["journalist.caption.articles"]</div>
}
@if (Model.UserCanManageOrganisationMembers)
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation/Members');">@Localiser["label.members"]</div>
}
@if (Model.UserCanManageOrganisationOpportunities)
{
<div class="dropdown-item text-dark sax-action" onclick="sax.goToPage('Organisation/Opportunities');">@Localiser["label.opportunities"]</div>
@@ -9,7 +9,7 @@
"EmailConfigs": {
"SAX-SF-Dev": {
"Message": {
"AddressFrom": "DoNotReply@solumforti.com"
"AddressFrom": "DoNotReply@sportierre.com"
},
"SMTP": {
"Server": "smtp.ionos.co.uk",
@@ -18,8 +18,8 @@
},
"Send": {
"Using": 2,
"UserName": "info@solumforti.com",
"Password": "solfor-info-5Ekur3"
"UserName": "info@sportierre.com",
"Password": "5p0rTi3rre-info-2021!"
}
}
}
@@ -1,57 +0,0 @@
{
"SessionConfigs": {
"Saxonite-Dev": {
"Environments": [ "Development" ],
"Instance": "Dev",
"CoreDatabase": {
"Location": "MsSql:Sarand106\\SQL2014.Saxonite_Dev",
"User": "saxonite",
"Password": "sax-dev-2021"
},
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "dev@solumforti.com" ]
}
},
"Documents": {
"RootFolder": "D:\\Saxonite\\Data\\Docs"
},
"Logging": {
"RootFolder": "D:\\Sarand\\Projects\\User\\AHoward\\VS2017\\Saxonite\\Logs"
}
},
"Saxonite-Test": {
"Environments": [ "Production" ],
"Instance": "QC",
"CoreDatabase": {
"Location": "MsSql:Sarand106\\SQL2014.Saxonite_Dev",
"User": "saxonite",
"Password": "sax-dev-2021"
},
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "qc@solumforti.com" ],
"AddressesBcc": [ ]
}
},
"Documents": {
"RootFolder": "D:\\Saxonite\\Data\\Docs"
},
"Logging": {
"RootFolder": "D:\\Sarand\\Projects\\User\\AHoward\\VS2017\\Saxonite\\QC\\Logs"
},
"Variants": [
{
"ApplicationRootFolder": "D:\\Sarand\\Projects\\User\\AHoward\\VS2017\\Saxonite\\QC2\\Bin",
"Instance": "QC",
"Logging": {
"RootFolder": "D:\\Sarand\\Projects\\User\\AHoward\\VS2017\\Saxonite\\QC2\\Logs"
}
}
]
}
}
}
@@ -1,5 +1,5 @@
{
"SessionConfigs": {
"AppConfigs": {
"Saxonite-Dev": {
"Environments": [ "Development" ],
"Instance": "Dev",
@@ -11,7 +11,7 @@
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "dev@solumforti.com" ]
"AddressesTo": [ "info@sportierre.com" ]
}
},
"Documents": {
@@ -32,8 +32,8 @@
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "qc@solumforti.com" ],
"AddressesBcc": [ ]
"AddressesTo": [ "info@sportierre.com" ],
"AddressesBcc": []
}
},
@@ -1,5 +1,5 @@
{
"SessionConfigs": {
"AppConfigs": {
"SAX-Prod": {
"Environments": [ "Production" ],
"Instance": "",
@@ -26,14 +26,14 @@
"Context": "SAX-SF-Prod",
"ContactUs": {
"AddressesTo": [],
"AddressesBcc": [ "dev@solumforti.com" ]
"AddressesBcc": [ "info@sportierre.com" ]
},
"Signup": {
"Activate": {
"AddressesBcc": [ "signup@solumforti.com" ]
"AddressesBcc": [ "info@sportierre.com" ]
},
"Welcome": {
"AddressesBcc": [ "signup@solumforti.com" ]
"AddressesBcc": [ "info@sportierre.com" ]
}
}
},
@@ -1,60 +0,0 @@
{
"SessionConfigs": {
"SAX-Prod": {
"Environments": [ "Production" ],
"Instance": "",
"CoreDatabase": {
"Location": "MsSql:.\\SQL2016EXP.Saxonite_Core_Live",
"User": "sax-prod-user",
"Password": "sax-live-202104"
},
"Security": {
"Password": {
"MinLength": 8
},
"SignIn": {
"KeepLoggedIn": {
"Allowed": true,
"CookieExpiresDays": 30
},
"PasswordRequest": {
"LinkExpiresMins": 30
}
}
},
"Email": {
"Context": "SAX-SF-Prod",
"ContactUs": {
"AddressesTo": [],
"AddressesBcc": [ "dev@solumforti.com" ]
},
"Signup": {
"Activate": {
"AddressesBcc": [ "signup@solumforti.com" ]
},
"Welcome": {
"AddressesBcc": [ "signup@solumforti.com" ]
}
}
},
"Documents": {
"RootFolder": "C:\\Sarand\\Saxonite\\Prod\\SaxoniteOnline\\Docs"
},
"Logging": {
"RootFolder": "C:\\Sarand\\Saxonite\\Prod\\SaxoniteOnline\\Logs"
},
"Variants": [
{
"ApplicationRootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteOnline\\Bin",
"Instance": "PreProd",
"Documents": {
"RootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteOnline\\Docs"
},
"Logging": {
"RootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteOnline\\Logs"
}
}
]
}
}
}
@@ -2,7 +2,7 @@
"EmailConfigs": {
"SAX-SF-Prod": {
"Message": {
"AddressFrom": "DoNotReply@solumforti.com"
"AddressFrom": "DoNotReply@sportierre.com"
},
"SMTP": {
"Server": "smtp.ionos.co.uk",
@@ -11,8 +11,8 @@
},
"Send": {
"Using": 2,
"UserName": "info@solumforti.com",
"Password": "solfor-info-5Ekur3"
"UserName": "info@sportierre.com",
"Password": "5p0rTi3rre-info-2021!"
}
}
}
@@ -7,6 +7,8 @@
--color-profile: var(--color-alt1);
}
/* Profile */
.sax-profile
{
margin: 12px 0;
@@ -39,6 +41,8 @@
background-color: #fff;
}
/* Profile sections */
.sax-profile .sax-panel-info,
.sax-profile .sax-panel-form
{
@@ -63,6 +67,12 @@
color: var(--color-primary-dark);
}
.sax-profile .sax-panel-info > .sax-content
{
max-height: 240px;
overflow-y: auto;
}
.sax-profile .sax-panel-results .sax-panel-info > .sax-header
{
text-align: left;
@@ -0,0 +1,37 @@
/*
Code Selection stylesheet.
*/
/* Panels */
.sax-codeSelect-codes
{
padding:2px 0;
background-color:#f0f0f0;
border: 1px solid #b0b0b0;
border-radius: 6px;
}
#dlgCodeSelect.sax-form button.sax-button
{
min-width: 80px;
margin: 4px 0;
}
.sax-panel-item.Code
{
margin: 2px 4px;
padding: 2px 4px;
background-color:#fff;
border: 2px solid #d8d8ff;
border-radius: 4px;
cursor:pointer;
}
.sax-panel-item.Code.sel
{
background-color: #ececff;
border-color: #8a8aff;
}
/* The End */
+44 -4
View File
@@ -130,9 +130,9 @@
.sax-panel-item
{
margin: 8px auto;
margin: 6px auto;
background-color: #f8f8f8;
border: solid 2px #979797;
border: solid 1px #979797;
border-radius: 6px;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
@@ -154,6 +154,11 @@
font-weight: bold;
}
.sax-panel-item > .sax-header .dropdown-menu
{
padding: 4px 8px;
}
.sax-panel-item > .sax-header .sax-action
{
border-radius: 4px;
@@ -177,7 +182,7 @@
.sax-panel-item > .sax-content
{
margin: 6px 8px;
margin: 4px 8px;
padding: 4px 4px;
}
@@ -191,7 +196,7 @@
.sax-panel-item.ProfileSport,
.sax-panel-item.ProfileSport > .sax-header
{
border-color: var(--color-alt2);
border-color: var(--color-alt4);
}
/* Organisations */
@@ -202,6 +207,14 @@
border-color: var(--color-alt3);
}
/* Members */
.sax-panel-item.Member,
.sax-panel-item.Member > .sax-header
{
border-color: var(--color-alt2);
}
/* Articles */
.sax-panel-item.Article,
@@ -228,4 +241,31 @@
background-color: var(--color-opportunity-pale);
}
/* Item statuses */
.sax-status-awa
{
color: darkorange;
}
.sax-status-atv
{
color: green;
}
.sax-status-ina
{
color: darkred;
}
.sax-status-hld
{
color: dodgerblue;
}
.sax-status-del
{
color: purple;
}
/* The End */
@@ -87,7 +87,7 @@
.sax-panel-info > .sax-content,
.sax-panel-form > .sax-content
{
padding: 12px 12px;
padding: 4px 8px;
background-color: #f8f8f8;
}
@@ -128,6 +128,13 @@
{
}
/* Form controls */
.sax-form .sax-form-control
{
margin: 0 0 8px 0;
}
.sax-form .sax-form-control .sax-caption,
.sax-form .sax-form-control .sax-label
{
@@ -156,11 +163,6 @@
/* Controls */
.sax-form .sax-form-control
{
margin: 0 0 12px 0;
}
.sax-form .sax-input, .sax-form .sax-textarea, .sax-form .sax-select
{
padding: 3px 8px 0 8px;
@@ -6,11 +6,6 @@
:root
{
/*
#556B2F Dark Olive Green
Ref. https://www.crispedge.com/color/556B2F
Darker: #445525, #33401c. Lighter: #768858, #99a682, #a6c275, #b7ce90.
*/
--color-primary: #556B2F;
--color-primary-dark: #425324;
--color-primary-light: #a0ac8b;
@@ -19,6 +14,7 @@
--color-alt1: #2f6b63;
--color-alt2: #452f6b;
--color-alt3: #6b2f37;
--color-alt4: #2f556b;
/* Activity colours */
--color-article-dark: #7339ac;
--color-article: #9966CC;
@@ -202,7 +202,7 @@
//sax.debug('addProfileSport');
let $dlg = sax.$dlg.profileSport;
$('.UserSportId,.ProfileSportExists,#ifProfileSportId,input.sax-input,select.sax-select', $dlg).val('');
$('#pbSelectSport', $dlg).show();
$('.SelectSport', $dlg).show();
$dlg.dialog('option', 'title', sax.dlg.title.addUserSport);
sax.openDialog($dlg, 480, 400);
}
@@ -224,7 +224,7 @@
$('#ifProfileSport', $dlg).val(item.sportName);
$('#cbProfileSportParticipation', $dlg).val(item.sportParticipationCode);
$('#cbProfileSportOfficiating', $dlg).val(item.sportOfficiatingCode);
$('#pbSelectSport', $dlg).hide();
$('.SelectSport', $dlg).hide();
$dlg.dialog('option', 'title', sax.dlg.title.updateUserSport);
sax.openDialog($dlg, 480, 400);
}
@@ -273,7 +273,7 @@
}
sax.onRefreshProfileOrganisationsInfo = function (response)
{
//sax.debug('onRefreshProfileOrganisationsInfo', response);
sax.debug('onRefreshProfileOrganisationsInfo', response);
if (!response || !response.success) return;
var $section = $('.sax-panel-section.ProfileOrganisations');
$('.sax-message', $section).stop(true, false).fadeOut(200).empty();
@@ -287,6 +287,10 @@
let item = items[itemIdx];
let $item = $tmpl.clone().prop('id', 'ProOrg_' + item.id);
$('.OrganisationName', $item).text(item.name);
$('.OrganisationSport', $item).text(item.sportName);
$('.OrganisationRegion', $item).text(item.regionName);
$('.OrganisationMemberCount', $item).toggle(!!item.memberCount).find('.MemberCount').text(item.memberCount);
$('.OrganisationOpportunityCount', $item).toggle(!!item.opportunityCount).find('.MemberCount').text(item.opportunityCount);
$items.append($item);
}
$items.show();
@@ -0,0 +1,123 @@
/*
* Code selection.
*/
(function (win, doc, undef)
{
"use strict";
let cs = sax.codeSelect = sax.codeSelect || { fn: {}, $dlg: {}, codeIdPrefix: 'Code_' };
//--------------------------------------------------------------
/*
* Code selection config:
* - caption - dialog title.
* - width: preferred dialog width (default: 400).
* - height: preferred dialog height (default: 400).
* - showFilter: whether to display filter control(s).
* - filterLabel: filter code field caption.
* - maxItems: maximum number of available items to list.
* - codes - list of {code,desc,comment} objects
* - selectedCodes - list of codes.
* - fnCallback - method to call on completion to store codes taking list of selected codes as parameter.
*/
cs.fn.openCodeSelect = function (cfg)
{
//sax.debug('openSelectCode', cfg);
cs.fn.init();
cs.cfg = cfg;
cs.selectedCodes = cfg.selectedCodes || [];
cs.fn.displayCodes(cfg.codes);
sax.openDialog(cs.$dlg.dialog('option', { title: cfg.caption || 'Select Codes' }), cs.cfg.width || 400, cs.cfg.height || 400);
}
cs.fn.displayCodes = function (codes)
{
let $codesAvail = $('.sax-codeSelect-codes.AvailableCodes').empty();
let $codesSelec = $('.sax-codeSelect-codes.SelectedCodes').empty();
let $codeTmpl = $('.sax-panel-item-template .sax-panel-item.Code');
for (let codeIdx = 0; codeIdx < codes.length; codeIdx++)
{
let code = codes[codeIdx];
let selected = cs.selectedCodes.indexOf(code.code) >= 0;
let $code = $codeTmpl.clone();
$($code).prop('id', cs.codeIdPrefix + code.code).attr('aria-code', code.code).on('click', function () { cs.fn.onClickCode(code.code); }).on('dblclick', function () { cs.fn.onDblClickCode(code.code); }).find('.CodeDesc').text(code.desc).end();
if (selected) $codesSelec.append($code);
else $codesAvail.append($code);
}
}
cs.fn.onClickCode = function (code)
{
$('.sax-panel-item.Code').removeClass('sel');
$('.sax-panel-item.Code[aria-code="' + code + '"]').addClass('sel');
}
cs.fn.onDblClickCode = function (code)
{
let codeIdx = cs.selectedCodes.indexOf(code);
//sax.debug('onDblClickCode', code, codeIdx);
if (codeIdx >= 0) cs.selectedCodes.splice(codeIdx, 1); else cs.selectedCodes.push(code)
cs.fn.displayCodes(cs.cfg.codes)
$('.sax-panel-item.Code[aria-code="' + code + '"]').addClass('sel');
}
cs.fn.onClickSelect = function ()
{
let codes = [];
$('.sax-codeSelect-codes.AvailableCodes .sax-panel-item.Code.sel').each(function (idx, el)
{
let code = $(el).attr('aria-code');
if (code)
{
codes.push(code);
cs.selectedCodes.push(code);
};
});
cs.fn.displayCodes(cs.cfg.codes)
for (const code of codes)
$('.sax-panel-item.Code[aria-code="' + code + '"]').addClass('sel');
}
cs.fn.onClickRemove = function ()
{
let codes = [];
$('.sax-codeSelect-codes.SelectedCodes .sax-panel-item.Code.sel').each(function (idx, el)
{
let code = $(el).attr('aria-code');
if (code)
{
let codeIdx = cs.selectedCodes.indexOf(code);
if (codeIdx >= 0)
{
codes.push(code);
cs.selectedCodes.splice(codeIdx, 1);
}
};
});
cs.fn.displayCodes(cs.cfg.codes)
for (const code of codes)
$('.sax-panel-item.Code[aria-code="' + code + '"]').addClass('sel');
}
cs.fn.storeSelectCode = function ()
{
//sax.debug('storeSelectCode', cs.cfg, cs.selectedCodes);
if (cs.cfg.fnCallback) cs.cfg.fnCallback(cs.selectedCodes);
cs.$dlg.dialog('close');
cs.fn.cleanUp();
}
cs.fn.cleanUp = function ()
{
delete cs.cfg;
delete cs.selectedCodes;
}
//--------------------------------------------------------------
cs.fn.init = function ()
{
if (!cs.$dlg) return;
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { cs.fn.storeSelectCode(); };
opt.buttons[sax.dlg.btn.cancel] = function () { cs.fn.cleanUp(); $(this).dialog('close'); };
cs.$dlg = $('#dlgCodeSelect').dialog(opt);
$('.sax-button.Select', cs.$dlg).on('click', function () { cs.fn.onClickSelect(); });
$('.sax-button.Remove', cs.$dlg).on('click', function () { cs.fn.onClickRemove(); });
}
}(window, window.document));
/* The End */
+28 -3
View File
@@ -70,6 +70,21 @@
}
sax.debug = sax.debugMode ? win.console.log.bind(win.console) : function () { };
//--------------------------------------------------------------
sax.compareCI = function (a, b)
{
var comparison = a.toLowerCase().localeCompare(b.toLowerCase());
if (comparison === 0)
return a.localeCompare(b);
return comparison;
}
sax.arraySortCI = function ()
{
if (!this) return this;
this.sort(function (a, b) { return sax.compareCI(a, b); });
return this;
};
//--------------------------------------------------------------
sax.setOddDataRowClass = function (rowSel, cName)
{
@@ -387,7 +402,7 @@
// Data entry.
sax.clearControlErrors = function (context)
{
var $ctrls = $('.sax-form-control', $(context)).removeClass('sax-error');
var $ctrls = $('.sax-form-control', $(context || doc.body)).removeClass('sax-error');
$('.sax-message', $ctrls).empty();
}
sax.clearControlError = function (sel)
@@ -402,8 +417,8 @@
}
sax.refreshControlValues = function (controlValues, context)
{
var $frmCtrls = $('.sax-form-control', $(context)).removeClass('sax-error');
sax.clearControlErrors();
var $frmCtrls = $('.sax-form-control', $(context || doc.body)).removeClass('sax-error');
sax.clearControlErrors(context);
var values = (controlValues || []);
var valuesLen = values.length;
for (var valIdx = 0; valIdx < valuesLen; valIdx++)
@@ -516,4 +531,14 @@
}(window, window.document));
//--------------------------------------------------------------
(function ()
{
if (typeof Object.defineProperty === 'function')
{
try { Object.defineProperty(Array.prototype, 'sortCI', { value: sax.arraySortCI }); } catch (e) { }
}
if (!Array.prototype.sortBy) Array.prototype.sortCI = sax.arraySortCI;
})();
/* The End */
@@ -0,0 +1,322 @@
/*
* Organisation - Members page scripts.
*/
(function (win, doc, undef)
{
"use strict";
sax.members = {};
sax.itemIdPrefix = 'Itm_';
//--------------------------------------------------------------
sax.refreshResults = function (delay)
{
sax.data.userCanManageMembers = false;
if (!sax.awaitingRefreshResponse)
{
var $items = $('.sax-panel-item-list', sax.$pnl.results).fadeOut(200).empty();
var $msgs = $('.sax-panel-messages', sax.$pnl.results).hide().empty().append($('<div class="sax-message">' + sax.msg.dataQuerying + '</div>')).fadeIn(200);
}
sax.ajax.refreshResults = sax.ajax.refreshResults || { url: sax.url.base + 'Organisation/Ajax/GetMemberList', formId: 'frmMemberFilter', callbackFn: sax.doRefreshResults };
sax.doAjaxRequest(sax.ajax.refreshResults, delay || 50);
sax.awaitingRefreshResponse = true;
}
sax.getFilterDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.Members li.sax-dropdown-item', sax.$pnl.filter).clone();
}
sax.getItemTemplate = function ()
{
return $('.sax-panel-item-template .sax-panel-item.Member', sax.$pnl.results).clone();
}
sax.getItemDropdownTemplate = function ()
{
return $('.sax-panel-item-template .sax-dropdown-menu.Member li.sax-dropdown-item', sax.$pnl.results).clone();
}
sax.doRefreshResults = function (response)
{
sax.debug('doRefreshResults', response);
delete sax.awaitingRefreshResponse;
sax.refreshControlValues(response.controlValues);
let $mnu = $('.sax-burger ul.sax-dropdown-menu', sax.$pnl.filter).empty();
var $msgs = $('.sax-panel-messages', sax.$pnl.results).hide().empty();
var $items = $('.sax-panel-item-list', sax.$pnl.results).hide().empty();
if (!response.success) return;
// Reference data - roles.
if (response.memberRoles && response.memberRoles.length)
sax.data.memberRoles = response.memberRoles;
// Menu.
$mnu.append(sax.getFilterMenuOption(sax.lbl.refresh, function () { sax.refreshResults(); }));
if (sax.data.userCanManageMembers = (response.user && response.user.canManage))
$mnu.append(sax.getFilterMenuOption(sax.lbl.add, function () { sax.createItem(); }));
$('.sax-burger', sax.$pnl.filter).toggle(!!$('.sax-dropdown-item', $mnu).length);
// Items.
var items = response.members;
if (!items.length)
return $msgs.append($('<div class="sax-message">' + sax.msg.dataNoneFound + '</div>')).fadeIn(500);
for (let itemIdx = 0; itemIdx < items.length; itemIdx++)
{
let item = items[itemIdx];
let $item = sax.getItemTemplate();
sax.populateItem($item, item);
$items.append($item);
}
$items.fadeIn(50);
}
sax.getFilterMenuOption = function (lbl, fn)
{
return sax.getMenuOption(sax.getFilterDropdownTemplate(), lbl, fn);
}
sax.getMenuOption = function ($opt, lbl, fn)
{
return $opt.find('div.sax-label').text(lbl).end().on('click', fn);
}
sax.populateItem = function ($item, item)
{
if (!item) return;
$item.prop('id', sax.itemIdPrefix + item.id);
$('.MemberEmail', $item).text(item.emailAddress);
$('.MemberDisplayName', $item).text(item.displayName);
$('.MemberAdminComment', $item).text(item.adminComment);
$('.MemberStatus', $item).text(item.statusDesc).addClass('sax-status-' + item.statusCode.toLowerCase());
let $mnu = $('ul.sax-dropdown-menu', $item).empty();
if (sax.data.userCanManageMembers)
{
let fnUpd = function () { sax.updateItem(item.id) };
$mnu.append(sax.getItemMenuOption(sax.lbl.edit, fnUpd));
if (!item.currentUser)
$mnu.append(sax.getItemMenuOption(sax.lbl.remove, function () { sax.removeItem(item.id) }));
if (item.awaiting)
$mnu.append(sax.getItemMenuOption(sax.lbl.activate, function () { sax.activateItem(item.id) }));
$('.sax-caption .sax-action', $item).off('click').on('click', fnUpd);
}
else $('.sax-caption .sax-action', $item).removeClass('sax-action');
$('.sax-burger', $item).toggle(!!$('.sax-dropdown-menu .sax-dropdown-item', $item).length);
$('.sax-panel-messages', sax.$pnl.results).hide().empty();
}
sax.getItemMenuOption = function (lbl, fn)
{
return sax.getMenuOption(sax.getItemDropdownTemplate(), lbl, fn);
}
//--------------------------------------------------------------
sax.selectFilterOrganisation = function ()
{
if (!sax.data.memberOrganisations)
sax.getMemberOrganisations(sax.showSelectOrganisation);
else sax.showSelectOrganisation();
}
sax.getMemberOrganisations = function (fnCallback)
{
let handleMemberOrganisationsResponse = function (response)
{
//sax.debug('handleUserOrgsResponse', response);
if (!response.success) return;
sax.data.memberOrganisations = response.organisations;
if (fnCallback) fnCallback();
}
sax.ajax.userOrgs = sax.ajax.userOrgs || { url: sax.url.base + 'Organisation/Ajax/GetMemberOrganisationList', formId: 'frmNavigate', callbackFn: handleMemberOrganisationsResponse };
sax.doAjaxRequest(sax.ajax.userOrgs);
}
sax.showSelectOrganisation = function ()
{
//sax.debug('sax.selectFilterOrganisation');
sax.selectOrganisation.fn.selectOrganisation({ caption: sax.dlg.title.selectOrganisation, items: sax.data.memberOrganisations, fnCallback: sax.onOrganisationSelected });
}
sax.onOrganisationSelected = function (id, name)
{
//sax.debug('sax.onOrganisationSelected', id, name);
$('#frmMemberFilter #ifFilterOrganisationId, #frmMember #ifMemberOrganisationId').val(id);
$('#frmMemberFilter #ifFilterOrganisation').val(name);
sax.refreshResults(50);
}
//--------------------------------------------------------------
sax.createItem = function ()
{
if (!sax.data.userCanManageMembers) return;
sax.clearItem();
$('.MemberOrganisationId', sax.$frm.member).val($('.FilterOrganisationId', sax.$frm.filter).val());
sax.$dlg.member.dialog('option', 'title', sax.dlg.title.createMember);
sax.openDialog(sax.$dlg.member, 600, 600);
}
sax.clearItem = function ()
{
sax.member = { roleCodes: [] };
let $frm = sax.$frm.member;
$('.MemberId,.MemberExists,.MemberRoleCodes,input[type="text"],textarea,select', $frm).val('');
$('.MemberEmailAddress', $frm).prop('readonly', false);
$('.MemberDisplayName,.MemberTitle,.MemberFirstName,.MemberLastName', $frm).hide();
sax.clearControlErrors();
}
sax.doCreateItem = function ()
{
sax.storeItem();
}
//--------------------------------------------------------------
sax.updateItem = function (id)
{
if (!sax.data.userCanManageMembers) return;
$('.MemberId', sax.$frm.memberId).val(id);
sax.ajax.updateItem = sax.ajax.updateItem || { url: sax.url.base + 'Organisation/Ajax/GetMember', formId: 'frmMemberId', callbackFn: sax.onUpdateItem };
sax.doAjaxRequest(sax.ajax.updateItem, 50);
}
sax.onUpdateItem = function (response)
{
//sax.debug('onUpdateItem', response);
sax.clearItem();
if (!response.success) return;
let $frm = sax.$frm.member;
let item = sax.member = response.member;
$('.MemberId', $frm).val(item.id);
$('.MemberExists', $frm).val(1);
$('.MemberOrganisationId', $frm).val();
$('.MemberEmailAddress', $frm).val(item.emailAddress).prop('readonly', true);
$('.MemberDisplayName', $frm).toggle(!item.awaiting).val(item.displayName);
$('.MemberTitle', $frm).toggle(!!item.awaiting).val(item.title);
$('.MemberFirstName', $frm).toggle(!!item.awaiting).val(item.firstName);
$('.MemberLastName', $frm).toggle(!!item.awaiting).val(item.lastName);
$('.MemberRoleCodes', $frm).val(item.roleCodes);
$('.MemberRoles', $frm).val(sax.getSelectedMemberRoleDescs().join('\n'));
$('.MemberAdminComment', $frm).val(item.adminComment);
sax.clearControlErrors();
sax.$dlg.member.dialog('option', 'title', sax.dlg.title.updateMember);
sax.openDialog(sax.$dlg.member, 600, 600);
}
sax.doUpdateItem = function ()
{
sax.storeItem();
}
//--------------------------------------------------------------
// Member Roles.
sax.selectMemberRoles = function ()
{
//sax.debug('selectMemberRoles',sax.data);
sax.codeSelectCfg = sax.codeSelectCfg || { caption: sax.dlg.title.selectRoles, width: 520, fnCallback: sax.updateMemberRoles };
sax.codeSelectCfg.codes = sax.data.memberRoles;
sax.codeSelectCfg.selectedCodes = sax.member.roleCodes || [];
sax.codeSelect.fn.openCodeSelect(sax.codeSelectCfg);
}
sax.updateMemberRoles = function (memberRoleCodes)
{
sax.debug('updateMemberRoles', memberRoleCodes);
let $frm = sax.$frm.member;
sax.member.roleCodes = memberRoleCodes;
$('.MemberRoleCodes',$frm).val(memberRoleCodes.join(sax.data.memberRoleCodeDelim));
$('.MemberRoles', $frm).val(sax.getSelectedMemberRoleDescs().join('\n'));
}
sax.getSelectedMemberRoleDescs = function ()
{
let roles = [];
sax.member.roleCodes.forEach(function (value) { roles.push(sax.getMemberRoleDesc(value)); })
return roles.sortCI();
}
sax.getMemberRoleDesc = function (roleCode)
{
let roleDesc = '';
sax.data.memberRoles.some(function (value) { if (value.code == roleCode) { roleDesc = value.desc; return true; } return false; })
return roleDesc || roleCode;
}
//--------------------------------------------------------------
sax.storeItem = function ()
{
let $frm = sax.$frm.member;
$('.MemberNameSupplied', $frm).val($('.MemberLastName', $frm).is(":visible") ? 1 : 0);
sax.ajax.storeItem = sax.ajax.storeItem || { url: sax.url.base + 'Organisation/Ajax/StoreMember', formId: 'frmMember', callbackFn: sax.onStoreItem };
sax.doAjaxRequest(sax.ajax.storeItem, 50);
}
sax.onStoreItem = function (response)
{
sax.debug('onStoreItem', response);
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
let $frm = sax.$frm.member;
if (response.memberNameRequired)
{
$('.MemberEmailAddress', $frm).prop('readonly', true);
$('.MemberTitle,.MemberFirstName,.MemberLastName', $frm).show();
return;
}
sax.$dlg.member.dialog('close');
var item = response.member;
var $item = $('#' + sax.itemIdPrefix + item.id);
if (!$item.length)
{
$item = sax.getItemTemplate();
$('.sax-panel-item-list', sax.$pnl.results).prepend($item).show();
}
sax.populateItem($item, item)
}
//--------------------------------------------------------------
sax.removeItem = function (id)
{
let fn = function ()
{
$('.MemberId', sax.$frm.memberId).val(id);
sax.ajax.removeItem = sax.ajax.removeItem || { url: sax.url.base + 'Organisation/Ajax/RemoveMember', formId: 'frmMemberId', callbackFn: sax.onItemRemoved };
sax.doAjaxRequest(sax.ajax.removeItem, 50);
}
sax.doConfirm(sax.dlg.title.remove, sax.msg.remove, fn);
}
sax.onItemRemoved = function (response)
{
if (!response.success) return;
var item = response.member;
var $item = $('#' + sax.itemIdPrefix + item.id);
//sax.debug(item, $item);
if ($item.length)
$item.remove();
}
//--------------------------------------------------------------
sax.activateItem = function (id)
{
let fn = function ()
{
$('.MemberId', sax.$frm.memberId).val(id);
sax.ajax.activateItem = sax.ajax.activateItem || { url: sax.url.base + 'Organisation/Ajax/ActivateMember', formId: 'frmMemberId', callbackFn: sax.onItemActivated };
sax.doAjaxRequest(sax.ajax.activateItem, 50);
}
sax.doConfirm(sax.dlg.title.activate, sax.msg.activate, fn);
}
sax.onItemActivated = function (response)
{
if (!response.success) return;
var item = response.member;
var $item = $('#' + sax.itemIdPrefix + item.id);
//sax.debug(item, $item);
if ($item.length)
sax.populateItem($item, item)
}
//--------------------------------------------------------------
$(function ()
{
sax.$pnl.members = $('#pnlMembers');
sax.$pnl.filter = $('.sax-panel-filter', sax.$pnl.members);
sax.$pnl.results = $('.sax-panel-results', sax.$pnl.members);
sax.$frm.filter = $('#frmMemberFilter');
$('.MemberFilter', sax.$frm.filter).on('input', function () { sax.refreshResults(250); }).on('keypress', function (event)
{
if (event.keyCode == 13) setTimeout(sax.refreshResults, 50);
});
sax.$frm.memberId = $('#frmMemberId');
sax.$frm.member = $('#frmMember');
$('.sax-input', sax.$frm.member).on('input', function () { sax.clearControlError(this); });
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.doCreateItem(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); };
sax.$dlg.member = $('#dlgMember').dialog(opt);
setTimeout(sax.refreshResults, 250);
});
}(window, window.document));
/* The End */
@@ -21,7 +21,7 @@
or.fn.storeOrganisation = function ()
{
//sax.debug('refreshResults');
or.ajax.registerOrg = or.ajax.registerOrg || { url: sax.url.base + 'Organisation/Ajax/requestOrganisation', formId: 'frmOrganisationRequest', callbackFn: or.fn.handleRequestOrganisationResponse };
or.ajax.registerOrg = or.ajax.registerOrg || { url: sax.url.base + 'Organisation/Ajax/Request', formId: 'frmOrganisationRequest', callbackFn: or.fn.handleRequestOrganisationResponse };
sax.doAjaxRequest(or.ajax.registerOrg, 50);
}
or.fn.handleRequestOrganisationResponse = function (response)