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
@@ -32,7 +32,7 @@ namespace Saxonite.Net.Core.Web.Admin.App
// Data members.
private bool generateDatabaseDefinitions = false;
private bool populateRegions = false;
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
@@ -75,8 +75,8 @@ namespace Saxonite.Net.Core.Web.Admin.App
}
public override String SessionCookieName { get { return Sax.Config.Admin.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.
@@ -107,15 +107,15 @@ namespace Saxonite.Net.Core.Web.Admin.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))
@@ -129,9 +129,9 @@ namespace Saxonite.Net.Core.Web.Admin.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);
@@ -38,7 +38,7 @@ namespace Saxonite.Net.Core.Web.Admin.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);
@@ -45,7 +45,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
if (StringUtil.IsEmpty(SessionConfig.URL.Online.Root))
if (StringUtil.IsEmpty(AppConfig.URL.Online.Root))
return Json(responseData.SetMessage(messageTitle, "Root online URL not specified."));
// Identify item.
@@ -74,13 +74,28 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
return Json(responseData);
}
//-------------------------------------------------------------------
private class OrganisationMemberData : SacsDisposable
{
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (UserOrganisation != null) UserOrganisation.Dispose(); UserOrganisation = null;
if (UserAccount != null) UserAccount.Dispose(); UserAccount = null;
}
}
public SaxUserOrganisation UserOrganisation { get; set; }
public SaxUserAccount UserAccount { get; set; }
}
//-------------------------------------------------------------------
// Activate Organisation ajax request.
//-------------------------------------------------------------------
[HttpPost]
[Route("Organisation/Ajax/Activate")]
[Route("Organisation/Ajax/ActivateItem")]
public IActionResult Ajax_Activate(Model_Organisation model)
public IActionResult Ajax_Activate(Model_OrganisationActivation model)
{
String fn = GetType().Name + ".Ajax_Activate";
String messageTitle = Localiser["organisation.caption.organisation"];
@@ -90,65 +105,115 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate item properties.
model.ValidateOrganisationData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Retrieve existing item.
SysId organisationId = model.OrganisationId.ToSysId();
SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId);
if (organisation == null && SysId.IsValid(organisationId))
using (SaxOrganisation organisation = AccountMgr.GetOrganisationById(organisationId))
{
SaLogger.Warn(fn + " Failed to retrieve organisation for Id: '" + model.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Activate organisation.
organisation.Status = Sarand.Net.Standard.Base.Core.SaStatus.Active;
if (!AccountMgr.UpdateOrganisation(organisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update organisation [Id:" + SysId.ToString(organisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
}
// Activate awaiting members and send welcome email to each.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
prmUserOrganisation.OrganisationIdsIncluded.Add(organisationId);
prmUserOrganisation.UserAccountStatusCat = SaxUserAccount.StatusCat.AwaitingOnly;
prmUserOrganisation.StatusCat = SaxUserOrganisation.StatusCat.ActiveOnly;
List<SaxUserOrganisation> userOrganisations = new List<SaxUserOrganisation>();
foreach (SaxUserOrganisation userOrganisation in userOrganisations)
{
using (SaxUserAccount userAccount = AccountMgr.GetUserAccountById(userOrganisation.UserAccountId))
if (organisation == null && SysId.IsValid(organisationId))
{
if (userAccount == null) continue;
userAccount.Status = SaStatus.Active;
if (AccountMgr.UpdateUserAccount(userAccount, DbUpdateInfo))
SaLogger.Warn(fn + " Failed to retrieve organisation for. : '" + model.OrganisationId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Retrieve users.
using (DisposableCollection<OrganisationMemberData> organisationMembersToActivate = new DisposableCollection<OrganisationMemberData>())
{
foreach (String userOrganisationId in model.OrganisationMemberIds)
{
// Send welcome email.
SaEmailData emailData = new SaEmailData();
emailData.Config = EmailConfig;
emailData.AddressesTo.Add(userAccount.EmailAddress);
emailData.Subject = Localiser["security.caption.request.password"];
PopulateAccountActivatedEmailBody(emailData, userAccount);
if (EmailConsole.SendEmail(emailData))
SaLogger.Info(fn + " Password request email sent to " + userAccount.EmailAddress, true);
else SaLogger.Warn(fn + " Failed to send password request email to " + userAccount.EmailAddress);
if (userOrganisationId == null) continue;
OrganisationMemberData organisationMember = new OrganisationMemberData();
organisationMember.UserOrganisation = AccountMgr.GetUserOrganisationById(userOrganisationId.ToSysId());
organisationMember.UserAccount = AccountMgr.GetUserAccountById(organisationMember.UserOrganisation?.UserAccountId ?? null);
if (organisationMember.UserOrganisation == null)
{
SaLogger.Warn(fn + " Failed to retrieve user organisation. Id: '" + userOrganisationId + "'");
organisationMember.Dispose();
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (organisationMember.UserAccount == null)
{
SaLogger.Warn(fn + " Failed to retrieve user account . Id: '" + organisationMember.UserOrganisation.UserAccountId + "'");
organisationMember.Dispose();
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
if (organisationMember.UserAccount.Status != SaStatus.Awaiting)
{
SaLogger.Warn(fn + " User organisation is not awaiting. Id: '" + userOrganisationId + "'. Status: " + organisationMember.UserAccount.StatusDesc);
organisationMember.Dispose();
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.system"]));
}
// Check if this user is to be activated.
bool activateUser = false;
String controlName_Activate = "MemberActivate_" + userOrganisationId;
foreach (String key in Request.Form.Keys)
{
if (key.EqualsCI(controlName_Activate))
{
activateUser = true;
break;
}
}
if (activateUser)
organisationMembersToActivate.Add(organisationMember);
else organisationMember.Dispose();
organisationMember = null;
}
else
if (organisationMembersToActivate.IsEmpty())
{
// No users to be activated.
// Check that organisation already has active members.
if (AccountMgr.GetOrganisationMemberCount(organisation.Id) < 1)
{
SaLogger.Warn(fn + " Unable to activate Organisation - no active members. Id: '" + SysId.ToString(organisationId));
return Json(responseData.SetMessage(messageTitle, Localiser["organisation.activate.msg.no.active.members"]));
}
}
// Activate organisation.
organisation.Status = Sarand.Net.Standard.Base.Core.SaStatus.Active;
if (!AccountMgr.UpdateOrganisation(organisation, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update organisation [Id:" + SysId.ToString(organisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
}
// Activate awaiting members and send welcome email to each.
foreach (OrganisationMemberData organisationMember in organisationMembersToActivate)
{
// Ensure that User Organisation has 'Member Admin' role.
if (organisationMember.UserOrganisation == null) continue;
organisationMember.UserOrganisation.AddOrganisationRole(Sax.OrganisationRole.MemberAdmin);
if (AccountMgr.UpdateUserOrganisation(organisationMember.UserOrganisation, DbUpdateInfo))
{
if (organisationMember.UserAccount == null) continue;
organisationMember.UserAccount.Status = SaStatus.Active;
if (AccountMgr.UpdateUserAccount(organisationMember.UserAccount, DbUpdateInfo))
{
// Send activation email.
SaEmailData emailData = new SaEmailData();
emailData.Config = EmailConfig;
emailData.AddressesTo.Add(organisationMember.UserAccount.EmailAddress);
emailData.Subject = Localiser["user.activate.email.subject"];
PopulateAccountActivatedEmailBody(emailData, organisationMember.UserAccount);
if (EmailConsole.SendEmail(emailData))
SaLogger.Info(fn + " User Activation email sent to " + organisationMember.UserAccount.EmailAddress, true);
else SaLogger.Warn(fn + " Failed to send User Activation email to " + organisationMember.UserAccount.EmailAddress);
}
else
SaLogger.Warn(fn + " Failed to update user account [Id:" + SysId.ToString(organisationMember.UserAccount.Id) + "]: " + AccountMgr.ErrorStateMessage);
}
else
SaLogger.Warn(fn + " Failed to update user organisation [Id:" + SysId.ToString(organisationMember.UserOrganisation.Id) + "]: " + AccountMgr.ErrorStateMessage);
}
// Construct response.
PopulateOrganisationResponseData(organisation, responseData.organisation);
}
}
// Construct response.
PopulateOrganisationResponseData(organisation, responseData.organisation);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
@@ -163,7 +228,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
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, "", SessionConfig.URL.Online.Root));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.RequestPassword]", SecurityController.GenerateRequestPasswordLink(this, userAccount.Id, userAccount.EmailAddress, "", AppConfig.URL.Online.Root));
SaEmailConsole.ReplaceDynamicEmailTag(emailData, "[#Link.ExpiresMinutes]", SecurityController.GetRequestPasswordEmailLinkExpiresMinutes(this).ToString());
}
@@ -21,9 +21,8 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
{
//-------------------------------------------------------------------
// Organisation data.
private class OrganisationData_List
private class OrganisationData_List : AjaxResponse_Data.ItemData_Base
{
public String Id { get; set; }
public String Name { get; set; }
public String TypeCode { get; set; }
public String TypeDesc { get; set; }
@@ -38,12 +37,6 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
public String RegionNameCountry { get; set; }
// Address.
public String AddressSummary { get; set; }
// Common properties.
public String StatusCode { get; set; }
public String StatusDesc { get; set; }
public Boolean Awaiting { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Awaiting)); } }
public Boolean Active { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Active)); } }
public Boolean Deleted { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Deleted)); } }
}
private class OrganisationData_Full : OrganisationData_List
{
@@ -46,9 +46,9 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
data.OrganisationId = SysId.ToString(organisation.Id);
data.OrganisationName = organisation.Name;
// Exclude 'Member' role.
foreach (Sax.OrganisationRole organisationRole in userOrganisation.OrganisationRoles.FindAll(item => item != Sax.OrganisationRole.Member))
foreach (Sax.OrganisationRole organisationRole in userOrganisation.GetOrganisationRoles().ToList().FindAll(item => item != Sax.OrganisationRole.Member))
data.RoleCodes.Add(OrganisationRoleCodes.GetCodeForType(organisationRole));
data.RoleCount = userOrganisation.OrganisationRoles.Count - 1;
data.RoleCount = userOrganisation.OrganisationRoleCount - 1;
data.StatusCode = userOrganisation.StatusCode;
data.StatusDesc = userOrganisation.StatusDesc;
}
@@ -113,7 +113,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
responseData.Success = true;
return Json(responseData);
}
private void GetOrganisationMembers (SaxModel_Admin model, SysId organisationId, List<MemberData_List> members)
private void GetOrganisationMembers(SaxModel_Admin model, SysId organisationId, List<MemberData_List> members)
{
// Item filter.
SaxUserOrganisation.Params prmUserOrganisation = new SaxUserOrganisation.Params();
@@ -312,8 +312,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
// Populate item properties.
if (model.MemberRoleCodes != null)
userOrganisation.OrganisationRoles = SaxUserOrganisation.GetOrganisationRolesFromCodes(model.GetMemberRoleCodes());
if (!userOrganisation.OrganisationRoles.Contains(Sax.OrganisationRole.Member))
userOrganisation.OrganisationRoles.Add(Sax.OrganisationRole.Member);
userOrganisation.AddOrganisationRole(Sax.OrganisationRole.Member);
if (model.MemberStatusCode != null)
userOrganisation.Status = model.MemberStatus;
@@ -57,18 +57,18 @@ namespace Saxonite.Net.Core.Web.Admin.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_Admin = keepLoggedIn;
@@ -78,7 +78,7 @@ namespace Saxonite.Net.Core.Web.Admin.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);
@@ -119,7 +119,7 @@ namespace Saxonite.Net.Core.Web.Admin.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);
}
@@ -79,7 +79,7 @@ namespace Saxonite.Net.Core.Web.Admin.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.
@@ -394,7 +394,7 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
}
internal static int GetRequestPasswordEmailLinkExpiresMinutes(SaxController_Admin 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));
@@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -16,6 +17,7 @@ using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Web;
@@ -88,7 +90,19 @@ namespace Saxonite.Net.Core.Web.Admin.Controllers
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. " + logSuffix);
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not 'Admin'. " + logSuffix);
else
{
// Account is active but not 'Admin'.
// Redirect to Online application if URL is available and not already redirected ('rpe2' parameter).
String redirectParamName = ParamName_RequestPasswordEncrypted + "2";
SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not 'Admin'. " + logSuffix);
if (!Request.Query.Keys.Contains(redirectParamName) && !StringUtil.IsEmpty(AppConfig.URL.Online.Root))
{
UriBuilder uri = new UriBuilder(Regex.Replace(AppConfig.URL.Online.Root,"/$","") + "/Security/ChangePassword");
uri.Query = ParamName_RequestPasswordEncrypted + "=" + Uri.EscapeDataString(encryptedParams) + "&" + redirectParamName;
return Redirect(uri.Uri.OriginalString);
}
}
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not active. " + logSuffix);
}
@@ -0,0 +1,44 @@
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Utils;
using Saxonite.Base.App;
using Saxonite.Net.Core.Web.Base.App;
using Saxonite.Net.Core.Web.Base.Controllers;
using Saxonite.Net.Core.Web.Base.Models;
using Saxonite.Net.Standard.Base.App;
using Saxonite.Net.Standard.Base.Bus;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace Saxonite.Net.Core.Web.Admin.Models
{
//=======================================================================
/// <summary>
/// Model for Organisation Activation.
/// <para>NB Only used for Ajax activation request.</para>
/// </summary>
public class Model_OrganisationActivation : SaxModel_Admin
{
//-------------------------------------------------------------------
// Construction.
public Model_OrganisationActivation(SaxLocaliser localiser) :
base(localiser)
{
}
//-------------------------------------------------------------------
// Organisation properties.
public String OrganisationId { get; set; }
/// <summary>
/// List of User Organisation Ids that were offered for activation.
/// </summary>
public List<String> OrganisationMemberIds { get; set; }
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -144,6 +144,12 @@
<data name="label.accounts" xml:space="preserve">
<value>Accounts</value>
</data>
<data name="label.activate" xml:space="preserve">
<value>Activate</value>
</data>
<data name="label.address" xml:space="preserve">
<value>Address</value>
</data>
<data name="label.any" xml:space="preserve">
<value>Any</value>
</data>
@@ -189,6 +195,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.email.address" xml:space="preserve">
<value>Email address</value>
</data>
@@ -381,6 +390,15 @@
<data name="msg.validation.maximum.length" xml:space="preserve">
<value>Value must not exceed {0} characters</value>
</data>
<data name="organisation.activate.intro" xml:space="preserve">
<value>On activation, the Organisation will become visible on the platform and authorised members will be able to post content associated with the organisation.</value>
</data>
<data name="organisation.activate.msg.no.active.members" xml:space="preserve">
<value>Organisation canot be activated without also activating at least one member.</value>
</data>
<data name="organisation.activate.organisation.header" xml:space="preserve">
<value>Organisation to activate:</value>
</data>
<data name="organisation.caption.member" xml:space="preserve">
<value>Organisation Member</value>
</data>
@@ -501,6 +519,9 @@
<data name="system.msg.database.schema.valid" xml:space="preserve">
<value>Database schema is valid.</value>
</data>
<data name="user.activate.email.subject" xml:space="preserve">
<value>Account Activation</value>
</data>
<data name="user.caption.select.user.roles" xml:space="preserve">
<value>Select User Roles</value>
</data>
@@ -8,8 +8,8 @@
<div class="sax-page-organisations">
<script type="text/javascript">
sax.lbl.edit = 'Edit';
sax.lbl.activate = 'Activate';
sax.lbl.edit = '@(Localiser.GetJavascriptText("label.edit"))';
sax.lbl.activate = '@(Localiser.GetJavascriptText("label.activate"))';
</script>
<div class="row">
@@ -139,7 +139,7 @@
</div>
@* Burger dropdown item template - ul is ignored *@
<ul class="sax-dropdown-menu Organisation">
<li class="sax-dropdown-item sax-action"><div class="sax-label">XXX</div></li>
<li class="sax-dropdown-item sax-action"><div class="sax-label">...</div></li>
</ul>
</div>
</div>
@@ -4,6 +4,35 @@
/* Organisations - Organisation dialog panel */
}
<style type="text/css">
table.OrganisationInfo
{
margin: 4px 8px 4px 16px;
}
table.OrganisationInfo .sax-label, table.OrganisationInfo .sax-value
{
font-size: .9rem;
}
table.OrganisationInfo .sax-label
{
padding-right: 8px;
text-align: right;
color: #808080;
font-weight: bold;
}
table.OrganisationMembers
{
margin: 4px 8px 4px 16px;
}
table.OrganisationMembers td
{
padding: 0 8px;
}
</style>
<script type="text/javascript">
</script>
<div id="dlgOrganisationActivation" class="sax-dialog" title="@Localiser.GetJavascriptText("organisation.caption.organisation.activate")">
@@ -12,11 +41,47 @@
{
@Html.HiddenFor(model => model.OrganisationId, new { @id = "", @class = "OrganisationId" })
<div>Introduction</div>
<div class="sax-para">@Localiser["organisation.activate.intro"]</div>
<div>Organisation details.</div>
<div class="sax-para">@Localiser["organisation.activate.organisation.header"]</div>
<table class="OrganisationInfo">
<tr class="OrganisationName">
<td class="sax-label">@Localiser["label.name"]</td>
<td class="sax-value "></td>
</tr>
<tr class="OrganisationCategory">
<td class="sax-label">@Localiser["label.category"]</td>
<td class="sax-value"></td>
</tr>
<tr class="OrganisationSport">
<td class="sax-label">@Localiser["label.sport"]</td>
<td class="sax-value"></td>
</tr>
<tr class="OrganisationRegion">
<td class="sax-label">@Localiser["label.region"]</td>
<td class="sax-value"></td>
</tr>
<tr class="OrganisationAddress">
<td class="sax-label">@Localiser["label.address"]</td>
<td class="sax-value"></td>
</tr>
</table>
<div>Members awaiting activation.</div>
<table class="OrganisationMembers"></table>
<div class="sax-panel-item-template">
<table>
<tr class="sax-item Member">
<td>
<input type="hidden" name="OrganisationMemberIds" class="MemberId" />
<input type="checkbox" class="MemberActivate" checked="checked" />
</td>
<td class="MemberEmail center"></td>
<td class="MemberName"></td>
</tr>
</table>
</div>
}
@@ -17,7 +17,7 @@
@if (!Model.RequestPasswordMode)
{
/* Current password - required when setting password within user session. */
<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 })
@@ -33,7 +33,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 })
@@ -45,7 +45,7 @@
<div class="sax-message"></div>
</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 })
@@ -14,7 +14,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmRequestPassword", @class = "sax-form" }))
{
<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>
@@ -15,7 +15,7 @@
@using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSignIn", @class = "sax-form" }))
{
<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>
@@ -25,7 +25,7 @@
<div class="sax-message"></div>
</div>
<div class="sax-form-control">
<div class="sax-form-control Password">
<div class="row">
<div class="col-6">
<div class="sax-label">
@@ -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,11 +1,11 @@
{
"SessionConfigs": {
"AppConfigs": {
"Saxonite-Dev": {
"Environments": [ "Development" ],
"Instance": "Dev",
"URLs": {
"Online": {
"Root": "https://localhost:44351/"
"Root": "https://localhost:44364/"
}
},
"CoreDatabase": {
@@ -16,7 +16,7 @@
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "dev@solumforti.com" ]
"AddressesTo": [ "info@sportierre.com" ]
}
},
"Documents": {
@@ -37,7 +37,7 @@
"Email": {
"Context": "SAX-SF-Dev",
"ContactUs": {
"AddressesTo": [ "qc@solumforti.com" ],
"AddressesTo": [ "info@sportierre.com" ],
"AddressesBcc": []
}
@@ -1,11 +1,11 @@
{
"SessionConfigs": {
"AppConfigs": {
"SAX-Prod": {
"Environments": [ "Production" ],
"Instance": "",
"URLs": {
"Online": {
"Root": "https://sarand.cloudapp.net:55443/"
"Root": "https://sportierre.com/"
}
},
"CoreDatabase": {
@@ -31,14 +31,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\\SaxoniteAdmin\\Docs"
},
"Logging": {
"RootFolder": "C:\\Sarand\\Saxonite\\Prod\\SaxoniteAdmin\\Logs"
},
"Variants": [
{
"ApplicationRootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteAdmin\\Bin",
"Instance": "PreProd",
"Documents": {
"RootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteAdmin\\Docs"
},
"Logging": {
"RootFolder": "C:\\Sarand\\Saxonite\\PreProd\\SaxoniteAdmin\\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!"
}
}
}
@@ -132,7 +132,7 @@
.sax-panel-item
{
margin: 8px auto;
margin: 6px auto;
border: solid 1px #979797;
border-radius: 6px;
-webkit-border-radius: 6px;
@@ -60,7 +60,7 @@
.sax-panel-form > .sax-content
{
max-height: 400px;
padding: 12px 12px;
padding: 4px 8px;
background-color: #f8f8f8;
overflow-y: auto;
}
@@ -122,6 +122,13 @@ button.accept-policy
line-height: inherit;
}
/* Information */
.sax-para
{
margin: 8px 0;
}
/* Page caption */
.sax-page-caption
{
+5 -5
View File
@@ -388,9 +388,9 @@
//--------------------------------------------------------------
// Data entry.
sax.clearControlErrors = function ()
sax.clearControlErrors = function (context)
{
var $ctrls = $('.sax-form-control').removeClass('sax-error');
var $ctrls = $('.sax-form-control', $(context || doc.body)).removeClass('sax-error');
$('.sax-message', $ctrls).empty();
}
sax.clearControlError = function (sel)
@@ -404,10 +404,10 @@
var $ctrl = $(sel).closest('.sax-form-control').addClass('sax-error');
$('.sax-message', $ctrl).text(error);
}
sax.refreshControlValues = function (controlValues)
sax.refreshControlValues = function (controlValues, context)
{
var $frmCtrls = $('.sax-form-control').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 < (controlValues || []).length; valIdx++)
@@ -265,8 +265,10 @@
sax.refreshControlValues(response.controlValues);
if (!response.success) return;
sax.$dlg.organisation.dialog('close');
var item = response.organisation;
sax.refreshItem(response.organisation);
}
sax.refreshItem=function(item)
{
var $item = $('#' + sax.itemIdPrefix + item.id);
if (!$item.length)
{
@@ -287,14 +289,48 @@
sax.showActivationInfo = function (response)
{
sax.debug('showActivationInfo', response);
if (!response.success || !response.organisation) return;
let item = response.organisation;
let $dlg = sax.$dlg.activate;
let $frm = $('#frmOrganisationActivation');
$('.OrganisationId', $frm).val($('.OrganisationId', sax.$frm.organisationId).val());
sax.openDialog(sax.$dlg.activate, 480, 640);
let popItemValue = function (sel, val)
{
$(sel, $frm).toggle(!!val).find('.sax-value').text(val);
}
popItemValue('.OrganisationName', item.name);
popItemValue('.OrganisationSport', item.sportName);
popItemValue('.OrganisationRegion', item.regionNameCountry);
popItemValue('.OrganisationCategory', item.categoryDesc);
popItemValue('.OrganisationAddress', item.addressSummary);
let $orgMbrs = $('.OrganisationMembers', $dlg).empty();
let $mbrTmpl = $('.sax-panel-item-template tr.sax-item.Member');
sax.debug(response.members, $orgMbrs, $mbrTmpl);
for (let idx = 0; idx < response.members.length; idx++)
{
let item = response.members[idx];
let $item = $mbrTmpl.clone();
$('.MemberId', $item).val(item.id);
$('.MemberActivate', $item).prop('name','MemberActivate_' + item.id)
$('.MemberEmail', $item).text(item.emailAddress);
$('.MemberName', $item).text(item.displayName);
$orgMbrs.append($item);
sax.debug($item);
}
sax.openDialog($dlg, 480, 640);
}
sax.axctivateOrganisation = function ()
sax.activateOrganisation = function ()
{
let $frm = $('#frmOrganisationActivation');
sax.ajax.activateOrganisation = sax.ajax.activateOrganisation || { url: sax.url.base + 'Organisation/Ajax/Activate', formId: $frm.prop('id'), callbackFn: sax.handleAtivateResponse };
sax.doAjaxRequest(sax.ajax.activateOrganisation, 50);
}
sax.handleAtivateResponse = function (response)
{
sax.debug('handleAtivateResponse', response);
if (!response.success) return;
sax.$dlg.activate.dialog('close');
sax.refreshItem(response.organisation);
}
//--------------------------------------------------------------
@@ -328,7 +364,7 @@
sax.$dlg.organisation = $('#dlgOrganisation').dialog(opt);
var opt = sax.dlgOpts();
opt.buttons[sax.dlg.btn.ok] = function () { sax.axctivateOrganisation(); };
opt.buttons[sax.dlg.btn.ok] = function () { sax.activateOrganisation(); };
opt.buttons[sax.dlg.btn.cancel] = function () { $(this).dialog('close'); };
sax.$dlg.activate = $('#dlgOrganisationActivation').dialog(opt);