Contacts page.

This commit is contained in:
2021-07-11 16:09:42 +01:00
parent 5043a629db
commit b8cfd87860
147 changed files with 1621 additions and 425 deletions
@@ -0,0 +1,332 @@
using Microsoft.AspNetCore.Mvc;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Net.Core.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Consoles;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
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.Helpers;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
//=======================================================================
// Portal Contact Controller - Ajax actions.
//=======================================================================
partial class ContactController
{
//-------------------------------------------------------------------
// Affiliate data.
private class AffiliateData_List : AjaxResponse_Data.ItemData
{
public String DisplayName { get; set; }
public String TypeCode { get; set; }
public String TypeDesc { get; set; }
// Address.
public String AddressSummary { get; set; }
}
private class AffiliateData_Full : AffiliateData_List
{
// Affiliate properties.
public String PhoneMain { get; set; } = "";
public String PhoneAlt { get; set; } = "";
public String PhoneFax { get; set; } = "";
public String Email { get; set; } = "";
public String Website { get; set; } = "";
// Ogranisation.
public SysId AffiliateIdParent { get; set; } = new SysId();
public String Name { get; set; } = "";
public String Abbr { get; set; } = "";
public String Nature { get; set; } = "";
public String Contact { get; set; } = "";
public String CompanyNo { get; set; } = "";
public String VatReg { get; set; } = "";
public String PhoneDirect { get; set; } = "";
// Individual.
public String Title { get; set; } = "";
public String Initials { get; set; } = "";
public String LastName { get; set; } = "";
public String FirstName { get; set; } = "";
public String Salutation { get; set; } = "";
public String PhoneMobile { get; set; } = "";
public byte BirthDay { get; set; } = 0;
public byte BirthMonth { get; set; } = 0;
public short BirthYear { get; set; } = 0;
public String MaritalStatus { get; set; } = "";
public String Spouse { get; set; } = "";
public String Children { get; set; } = "";
public String Hometown { get; set; } = "";
public SysId UserId { get; set; } = new SysId();
}
private void PopulateAffiliateResponseData(SbmAffiliate affiliate, AffiliateData_List data)
{
data.Id = SysId.ToString(affiliate.Id);
data.DisplayName = affiliate.GetDisplayName();
data.TypeCode = Internals.AffiliateTypeCodes.GetCodeForType(affiliate.AffiliateType);
data.TypeDesc = Internals.AffiliateTypeCodes.GetDescForType(affiliate.AffiliateType);
// Common properties.
data.Notes = affiliate.Notes;
data.StatusCode = affiliate.StatusCode;
data.StatusDesc = affiliate.StatusDesc;
}
private void PopulateAffiliateResponseData(SbmAffiliate affiliate, AffiliateData_Full data)
{
PopulateAffiliateResponseData(affiliate, data as AffiliateData_List);
// Affiliate properties.
data.PhoneMain = affiliate.PhoneMain;
data.PhoneAlt = affiliate.PhoneAlt;
data.PhoneFax = affiliate.PhoneFax;
data.Email = affiliate.Email;
data.Website = affiliate.Website;
// Ogranisation.
data.AffiliateIdParent = affiliate.AffiliateIdParent;
data.Name = affiliate.Name;
data.Abbr = affiliate.Abbr;
data.Nature = affiliate.Nature;
data.Contact = affiliate.Contact;
data.CompanyNo = affiliate.CompanyNo;
data.VatReg = affiliate.VatReg;
data.PhoneDirect = affiliate.PhoneDirect;
// Individual.
data.Title = affiliate.Title;
data.Initials = affiliate.Initials;
data.LastName = affiliate.LastName;
data.FirstName = affiliate.FirstName;
data.Salutation = affiliate.Salutation;
data.PhoneMobile = affiliate.PhoneMobile;
data.BirthDay = affiliate.BirthDay;
data.BirthMonth = affiliate.BirthMonth;
data.BirthYear = affiliate.BirthYear;
data.MaritalStatus = affiliate.MaritalStatus;
data.Spouse = affiliate.Spouse;
data.Children = affiliate.Children;
data.Hometown = affiliate.Hometown;
data.UserId = affiliate.UserId;
}
//-------------------------------------------------------------------
// Contact list.
//-------------------------------------------------------------------
private class AjaxResponse_ContactList : AjaxResponse_Data
{
// Construction.
public AjaxResponse_ContactList(SbmModel_Portal model) : base(model) { }
// Affiliate list.
public List<AffiliateData_List> Affiliates { get; } = new List<AffiliateData_List>();
// Reference data.
public List<CodeDesc> Statuses { get; } = new List<CodeDesc>();
public String DefaultStatusCode { get; set; }
}
// Ajax request.
[HttpPost]
[Route("Contact/Ajax/List")]
[Route("Contact/Ajax/GetList")]
public IActionResult Ajax_ContactList(Model_Contact model)
{
String fn = GetType().Name + ".Ajax_ContactList";
AjaxResponse_ContactList responseData = new AjaxResponse_ContactList(model);
String messageTitle = Localiser["contact.caption.contacts"];
// Validate session and referrer.
if (!ValidUserSession) return GetAjaxResult_InvalidSession(responseData);
if (!ValidReferer) return Forbid();
RefreshModel(model);
// Reference data - statuses.
foreach (SaStatus status in SbmAffiliate.ValidStatuses.FindAll(item => item != SaStatus.Deleted))
responseData.Statuses.Add(SacsSystem.GetStatusCode(status), Localiser.GetStatusCaption(status));
responseData.DefaultStatusCode = SacsSystem.GetStatusCode(SbmAffiliate.DefaultStatus);
// Item filter.
SbmAffiliate.Params prmAffiliate = new SbmAffiliate.Params();
prmAffiliate.Search = model.Filter.AffiliateSearch;
prmAffiliate.AffiliateType = model.GetFilterAffiliateType();
prmAffiliate.StatusCat = SbmAffiliate.StatusCat.NotDeleted;
prmAffiliate.SortColumns.Add(AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Name));
prmAffiliate.SortColumns.Add(AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.LastName));
model.Paging.ItemTotal = (ulong)AccountMgr.GetAffiliateCount(prmAffiliate);
model.PopulatePagingTo(prmAffiliate.ResultsPaging);
// Item columns.
ColumnDfn colId = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Id);
ColumnDfn colName = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Name);
ColumnDfn colAffiliateType = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Type);
ColumnDfn colPhoneMain = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneMain);
ColumnDfn colPhoneAlt = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.PhoneAlt);
ColumnDfn colNotes = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Notes);
ColumnDfn colStatus = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.Status);
ColumnDfn colCreatedOn = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.CreateOn_Date);
ColumnDfn colUpdatedOn = AccountMgr.GetAffiliateColumnDfn(SbmAffiliate.Column.UpdateOn_Date);
List<ColumnDfn> columns = new List<ColumnDfn>()
{
colId,
colName,
colAffiliateType,
colPhoneMain,
colPhoneAlt,
colNotes, colStatus, colCreatedOn, colUpdatedOn
};
// Query items.
using (DbResultSet resultSet = AccountMgr.ExecuteAffiliateQuery(columns, prmAffiliate))
{
while (resultSet != null && resultSet.HasRows && resultSet.NextRecord())
{
NamedValue.Map values = resultSet.GetRecordValues();
Sbm.AffiliateType affiliateType = (Sbm.AffiliateType)values.GetLong(colAffiliateType.DataName);
AffiliateData_List affiliateData = new AffiliateData_List()
{
Id = values.GetString(colId.DataName),
DisplayName = values.GetString(colName.DataName),
TypeCode = Internals.AffiliateTypeCodes.GetCodeForType(affiliateType),
TypeDesc = Internals.AffiliateTypeCodes.GetDescForType(affiliateType),
Notes = values.GetString(colNotes.DataName),
StatusCode = values.GetString(colStatus.DataName),
StatusDesc = SacsSystem.GetStatusDescForCode(values.GetString(colStatus.DataName))
};
responseData.Affiliates.Add(affiliateData);
}
}
if (model.Paging.IsPaged)
model.Paging.ItemCount = (ushort)responseData.Affiliates.Count;
// Complete response.
responseData.SetPaging(model);
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Get Affiliate ajax request.
//-------------------------------------------------------------------
private class AjaxResponse_Affiliate : AjaxResponse_Data
{
// Construction.
public AjaxResponse_Affiliate(SbmModel_Portal model) : base(model) { }
// Affiliate details.
public AffiliateData_Full affiliate { get; } = new AffiliateData_Full();
}
//-------------------------------------------------------------------
[HttpPost]
[Route("Contact/Ajax/Item")]
[Route("Contact/Ajax/GetItem")]
public IActionResult Ajax_GetItem(Model_Contact model)
{
String fn = GetType().Name + ".Ajax_GetItem";
String messageTitle = Localiser["affiliate.caption.affiliate"];
AjaxResponse_Affiliate responseData = new AjaxResponse_Affiliate(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Identify item.
SysId affiliateId = model.AffiliateId.ToSysId();
if (!SysId.IsValid(affiliateId))
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.specified"]));
// Retrieve item.
SbmAffiliate affiliate = AccountMgr.GetAffiliateById(affiliateId);
if (affiliate == null)
{
SaLogger.Warn(fn + " Failed to retrieve affiliate for Id: '" + model.AffiliateId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Construct response.
PopulateAffiliateResponseData(affiliate, responseData.affiliate);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
// Store Affiliate ajax request.
//-------------------------------------------------------------------
[HttpPost]
[Route("Contact/Ajax/Store")]
[Route("Contact/Ajax/StoreItem")]
public IActionResult Ajax_StoreItem(Model_Contact model)
{
String fn = GetType().Name + ".Ajax_StoreItem";
String messageTitle = Localiser["affiliate.caption.affiliate"];
AjaxResponse_Affiliate responseData = new AjaxResponse_Affiliate(model);
// Validate session.
if (!ValidUserSession)
return GetAjaxResult_InvalidSession(responseData);
// Validate item properties.
model.ValidateAffiliateData(responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Retrieve existing item.
SysId affiliateId = model.AffiliateId.ToSysId();
SbmAffiliate affiliate = AccountMgr.GetAffiliateById(affiliateId);
if (affiliate == null && SysId.IsValid(affiliateId))
{
SaLogger.Warn(fn + " Failed to retrieve affiliate for Id: '" + model.AffiliateId + "'");
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.id.not.found"]));
}
// Create new item if required.
if (affiliate == null)
affiliate = AccountMgr.CreateAffiliate(model.GetAffiliateType());
// Populate item properties.
if (model.AffiliateName != null)
affiliate.Name = model.AffiliateName;
// Common properties.
if (model.AffiliateNotes != null)
affiliate.Notes = model.AffiliateNotes;
if (model.AffiliateStatus != null)
affiliate.Status = model.GetAffiliateStatus();
// Store item.
if (!SysId.IsValid(affiliate.Id))
{
if (!AccountMgr.InsertAffiliate(affiliate, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to insert affiliate: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.insert.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
}
}
else
{
if (!AccountMgr.UpdateAffiliate(affiliate, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update affiliate [Id:" + SysId.ToString(affiliate.Id) + "]: " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetMessage(messageTitle, Localiser["msg.error.item.update.failed"] + "\n\n" + AccountMgr.ErrorStateMessage));
}
}
// Construct response.
PopulateAffiliateResponseData(affiliate, responseData.affiliate);
// Complete response.
responseData.Success = true;
return Json(responseData);
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -0,0 +1,60 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Net.Core.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Security;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
//=======================================================================
public partial class ContactController : SbmController_Portal
{
//-------------------------------------------------------------------
// Data members.
//-------------------------------------------------------------------
// Construction.
public ContactController(SbmLocaliser localiser, ILogger<ContactController> logger) :
base(localiser, logger)
{
}
//-------------------------------------------------------------------
[HttpGet]
public IActionResult Index()
{
String fn = GetType().Name + ".Index";
if (!ValidUserSession)
return RedirectToAction("", "");
// Contact page.
Model_Contact model = new Model_Contact(Localiser);
model.Paging.PageNo = SessionData.Contacts.Filter.PageNo;
model.Paging.PageLength = SessionData.Contacts.Filter.PageLength;
return View(model);
}
//-------------------------------------------------------------------
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel(Localiser) { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
//-------------------------------------------------------------------
}
//=======================================================================
}
@@ -41,62 +41,54 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
// NB Only allowed if there isn't a current user session.
if (!ValidUserSession && AppConfig.Security.SignIn.KeepLoggedIn.Allowed)
{
// Extract parameters and validate that they are populated.
String encryptedParams = GetRequestCookie(CookieName_KeepLoggedIn);
KeepLoggedInParams keepLoggedInParams = ExtractKeepLoggedInParams(encryptedParams);
String logPrefix = fn + " 'Keep Logged In' cookie found but ";
String logSuffix = keepLoggedInParams.GetValidParams().Concat("", " ", ".");
if (SysId.IsValid(keepLoggedInParams.SecurityItemId) && SysId.IsValid(keepLoggedInParams.AffiliateId))
if (keepLoggedInParams.IsValid())
{
// User may be defined on any one of the BusinessMgr databases - need to find out which.
// Identify session contexts with a BusMgr database that hosts the specified email address.
List<ushort> sessionContextIdxs = SbmSessionContextHelper_Web.GetSessionContextIdxsForUsersBusMgrDatabase(keepLoggedInParams.EmailAddress);
foreach (ushort sessionContextIdx in sessionContextIdxs)
{
// Consoles and Managers must be associated with the specific context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Web.GetSessionContext(sessionContextIdx);
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SaSecurityConsole securityConsole = App.CreateSecurityConsole(userContext))
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{
SaSecurityItem securityItemUser = securityConsole.GetUserByEmail(keepLoggedInParams.EmailAddress);
if (securityItemUser != null)
using (SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(keepLoggedInParams.EmailAddress))
using (SbmAffiliate affiliateUser = accountMgrForUser.GetAffiliateById(keepLoggedInParams.AffiliateId))
{
if (securityItemUser.Id.Equals(keepLoggedInParams.SecurityItemId))
if (securityItemUser != null && affiliateUser != null)
{
using (SbmAccountMgr accountMgr = App.System.CreateAccountMgr(userContext))
if (securityItemUser.Id.Equals(keepLoggedInParams.SecurityItemId) && affiliateUser.UserId.Equals(securityItemUser.Id))
{
SbmAffiliate affiliateUser = accountMgr.GetAffiliateById(keepLoggedInParams.AffiliateId);
if (affiliateUser != null)
if (affiliateUser.IsStatusCurrent)
{
if (affiliateUser.Id.Equals(keepLoggedInParams.AffiliateId))
String errorMessage = "";
if (SignUserIn(userContext, securityItemUser, affiliateUser, true, ref errorMessage))
{
if (affiliateUser.UserId.Equals(securityItemUser.Id))
{
if (affiliateUser.IsStatusActive)
{
String errorMessage = "";
if (SignUserIn(sessionContext, securityItemUser, affiliateUser, true, ref errorMessage))
SaLogger.Info(fn + " Keep Logged In cookie found." + logSuffix);
else SaLogger.Warn(fn + " Keep Logged In cookie found but failed to sign user in: " + errorMessage + "." + logSuffix);
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Affiliate is not active." + logSuffix);
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Affiliate User Id does not match security item." + logSuffix);
SaLogger.Info(logPrefix + " 'Keep Logged In' cookie found." + logSuffix);
break;
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Affiliate does nto match Id." + logSuffix);
else SaLogger.Warn(logPrefix + "failed to sign user in: " + errorMessage + "." + logSuffix);
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Affiliate not found." + logSuffix);
else SaLogger.Warn(logPrefix + "Affiliate is not active." + logSuffix);
}
else SaLogger.Warn(logPrefix + "Security Item and Affiliate are inconsistent. " + logSuffix);
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Security Item does not match Id." + logSuffix);
else SaLogger.Warn(logPrefix + "Security Item or Affiliate not found. " + logSuffix);
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Security Item not found by email." + logSuffix);
}
if (ValidUserSession)
break;
}
}
else SaLogger.Warn(fn + " Keep Logged In cookie found but Security Item or Affiliate Ids missing." + logSuffix);
else if (!StringUtil.IsEmpty(encryptedParams))
SaLogger.Warn(fn + " Keep Logged In cookie found but with incomplete details." + logSuffix);
}
// Redirect to sign-in if not signed-in.
@@ -4,6 +4,7 @@ using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Core.Web.Portal.App;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Core;
@@ -27,7 +28,7 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
//-------------------------------------------------------------------
// Protected construction.
protected SbmController_Portal(SbmLocaliser localiser, Microsoft.Extensions.Logging.ILogger<HomeController> logger) : base(localiser)
protected SbmController_Portal(SbmLocaliser localiser, Microsoft.Extensions.Logging.ILogger<SbmController_Portal> logger) : base(localiser)
{
}
@@ -50,42 +51,60 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
/// <para>- Open user session - store details against Sesion Data.</para>
/// <para>- Set 'Keep logged in' cookie if required.</para>
/// </summary>
protected bool SignUserIn(SbmSessionContext sessionContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, bool keepLoggedIn, ref String errorMessage)
protected bool SignUserIn(SbmUserContext userContext, SaSecurityItem securityItemUser, SbmAffiliate affiliateUser, bool keepLoggedIn, ref String errorMessage)
{
String fn = GetType().Name + ".SignUserIn";
// Validate User Account, just in case - should have been done before arriving here!
if (affiliateUser == null)
// Validate Security Item and Affiliate, just in case - should have been done before arriving here!
if (securityItemUser == null)
{
SaLogger.Error(fn + " Unable to sign account in - null user account.");
errorMessage = Localiser["security.msg.signin.failed"];
SaLogger.Error(fn + " Unable to sign account in - null security item.");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (!affiliateUser.IsStatusActive)
if (affiliateUser == null)
{
SaLogger.Error(fn + " Unable to sign account in - user account is not active. Email: " + affiliateUser.Email);
errorMessage = Localiser["security.msg.signin.failed"];
SaLogger.Error(fn + " Unable to sign account in - null affiliate.");
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
if (!affiliateUser.IsStatusCurrent)
{
SaLogger.Error(fn + " Unable to sign account in - affiliate is not active. Email: " + securityItemUser.EmailAddress);
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// 'Keep logged in' can be switched off by the application configuration.
keepLoggedIn = App.AppConfig.Security.SignIn.KeepLoggedIn.Allowed && keepLoggedIn;
// Log user in.
affiliateUser.KeepLoggedIn_Portal = keepLoggedIn;
//affiliateUser.LastLoginAt = DateTime.Now;
//affiliateUser.InvalidLoginCount = 0;
//affiliateUser.LastInvalidLoginAt = DateTime.MinValue;
if (!AccountMgr.UpdateAffiliate(affiliateUser, DbUpdateInfo))
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{
SaLogger.Warn(fn + " Failed to update account for " + affiliateUser.Email + ": " + AccountMgr.ErrorStateMessage);
errorMessage = Localiser["security.msg.signin.failed"];
return false;
// Log user in.
securityItemUser.LastLogin = DateTime.Now;
securityItemUser.InvalidLoginCount = 0;
securityItemUser.LastInvalidLoginAt = DateTime.MinValue;
if (!securityConsoleForUser.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update security item for " + securityItemUser.EmailAddress + ": " + securityConsoleForUser.ErrorStateMessage);
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
// Update affiliate.
affiliateUser.KeepLoggedIn_Portal = keepLoggedIn;
if (!accountMgrForUser.UpdateAffiliate(affiliateUser, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to update affiliate for " + securityItemUser.EmailAddress + ": " + accountMgrForUser.ErrorStateMessage);
errorMessage = Localiser["security.msg.signin.invalid"];
return false;
}
SaLogger.Info(fn + " User session opened for " + securityItemUser.EmailAddress, true);
}
SaLogger.Info(fn + " User session opened for " + affiliateUser.Email, true);
// Create session.
OpenUserSession(sessionContext, securityItemUser, affiliateUser);
OpenUserSession(userContext.SessionContext, securityItemUser, affiliateUser);
// Send the 'Keep Logged In' cookie if requested.
if (affiliateUser.KeepLoggedIn_Portal)
@@ -116,7 +135,7 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
// Validate user properties.
if (!SysId.IsValid(affiliateUser.Id)) return false;
if (StringUtil.IsEmpty(affiliateUser.Email)) return false;
if (StringUtil.IsEmpty(securityItemUser.EmailAddress)) return false;
// Close previous session.
CloseUserSession();
@@ -186,10 +205,22 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
public List<String> GetValidParams()
{
List<String> values = new List<String>();
if (!StringUtil.IsEmpty(EmailAddress))
values.Add("EmailAddress: " + EmailAddress);
if (SysId.IsValid(SecurityItemId))
values.Add("SecurityItemId: " + SysId.ToString(SecurityItemId));
if (SysId.IsValid(AffiliateId))
values.Add("UserAccountId: " + SysId.ToString(AffiliateId));
return values;
}
/// <summary>Verifiy that the email and account Ids are populated and the data hasn't expired.</summary>
public bool IsValid()
{
return
!StringUtil.IsEmpty(EmailAddress) &&
SysId.IsValid(SecurityItemId) &&
SysId.IsValid(AffiliateId);
}
}
public KeepLoggedInParams ExtractKeepLoggedInParams(String encryptedParams)
{
@@ -25,7 +25,7 @@ using System.Web;
namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
//=======================================================================
// Online Security Controller - Ajax actions.
// Portal Security Controller - Ajax actions.
//=======================================================================
partial class SecurityController
{
@@ -72,7 +72,7 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
return Json(responseData);
String errorMessage = "";
if (!SignUserIn(sessionContext, securityItemUser, affiliateUser, model.KeepMeSignedIn, ref errorMessage))
if (!SignUserIn(userContext, securityItemUser, affiliateUser, model.KeepMeSignedIn, ref errorMessage))
return Json(responseData.SetControlError(nameof(model.EmailAddress), errorMessage));
}
}
@@ -122,23 +122,25 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
String fn = GetType().Name + ".GetSecurityItemForSignin";
SaSecurityItem securityItemUser = null;
using (SaSecurityConsole securityConsole = App.CreateSecurityConsole(userContext))
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
{
// Retrieve security item by email address.
securityItemUser = securityConsole.GetUserByEmail(model.EmailAddress);
if (securityItemUser != null)
using (securityItemUser = securityConsoleForUser.GetUserByEmail(model.EmailAddress))
{
// Validate password.
if (!SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password) && !(DebugMode && model.EmailAddress.EqualsCI("ahoward@sarand.com")))
if (securityItemUser != null)
{
// Record invalid login attempt.
securityItemUser.InvalidLoginCount++;
securityItemUser.LastInvalidLoginAt = DateTime.Now;
if (!securityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
SaLogger.Warn(fn + " Failed to store invalid sign-in attempt against User: " + model.EmailAddress + ". " + AccountMgr.ErrorStateMessage, true);
SaLogger.Warn(fn + " Attempt to sign-in to User " + model.EmailAddress + " with invalid password. Attempt: " + securityItemUser.InvalidLoginCount, true);
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
securityItemUser = null;
// Validate password.
if (!SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password) && !(DebugMode && model.EmailAddress.EqualsCI("ahoward@sarand.com")))
{
// Record invalid login attempt.
securityItemUser.InvalidLoginCount++;
securityItemUser.LastInvalidLoginAt = DateTime.Now;
if (!securityConsoleForUser.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
SaLogger.Warn(fn + " Failed to store invalid sign-in attempt against User: " + model.EmailAddress + ". " + AccountMgr.ErrorStateMessage, true);
SaLogger.Warn(fn + " Attempt to sign-in to User " + model.EmailAddress + " with invalid password. Attempt: " + securityItemUser.InvalidLoginCount, true);
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
securityItemUser = null;
}
}
}
}
@@ -150,18 +152,20 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
String fn = GetType().Name + ".GetAffiliateForSignin";
SbmAffiliate affiliate = null;
using (SbmAccountMgr accountMgr = App.System.CreateAccountMgr(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{
// Identify the contact asociated with the security item.
SbmAffiliate.Params prmAffiliate = new SbmAffiliate.Params();
prmAffiliate.UserId = securityItemUser.Id;
prmAffiliate.StatusCat = SbmAffiliate.StatusCat.ActiveOnly;
affiliate = accountMgr.GetAffiliate(prmAffiliate);
if (affiliate != null)
prmAffiliate.StatusCat = SbmAffiliate.StatusCat.CurrentOnly;
using (affiliate = accountMgrForUser.GetAffiliate(prmAffiliate))
{
if (affiliate != null)
{
}
if (affiliate == null && !responseData.HasControlErrors())
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
}
if (affiliate == null && !responseData.HasControlErrors())
responseData.SetControlError(nameof(model.EmailAddress), model.Localiser["security.msg.signin.invalid"]);
}
return affiliate;
}
@@ -255,8 +259,12 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
String messageTitle = Localiser["security.caption.change.password"];
// Validate referrer.
if (!ValidReferer)
return Forbid();
if (!ValidReferer) return Forbid();
// If user is logged in, session Consoles and Managers can be used.
// If 'Request Password' parameters are specified, Consoles and Managers must be associated with the specific database for the user.
SbmSessionContext sessionContextForUser = null;
SbmUserContext_Web userContextForUser = null;
// If 'Request Password' encrypted params (from email link) are present,
// Session is not required and password can be set directly against the user.
@@ -267,68 +275,100 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(model.rpe);
if (requestPasswordParams.IsValid())
{
// Retrieve user details and validate email address.
securityItemUser = SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, requestPasswordParams.SecurityItemId);
affiliateUser = AccountMgr.GetAffiliateById(requestPasswordParams.AffiliateId);
if (requestPasswordParams.IsValid(securityItemUser, affiliateUser))
// User may be defined on any one of the BusinessMgr databases - need to find out which.
// Identify session contexts with a BusMgr database that hosts the specified email address.
List<ushort> sessionContextIdxs = SbmSessionContextHelper_Web.GetSessionContextIdxsForUsersBusMgrDatabase(requestPasswordParams.EmailAddress);
foreach (ushort sessionContextIdx in sessionContextIdxs)
{
validRequestPasswordParams = true;
validSessionRequired = false;
}
else
{
SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. SecurityItemId: " + SysId.ToString(requestPasswordParams.SecurityItemId) + ". AffiliateId: " + SysId.ToString(requestPasswordParams.AffiliateId) + ". Email: " + requestPasswordParams.EmailAddress);
affiliateUser = null;
// Consoles and Managers must be associated with the specific context.
sessionContextForUser = SbmSessionContextHelper_Web.GetSessionContext(sessionContextIdx);
userContextForUser = new SbmUserContext_Web(sessionContextForUser);
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContextForUser))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContextForUser))
{
// Retrieve user details and validate email address.
securityItemUser = securityConsoleForUser.GetSecurityItemById(SaSecurity.ItemType.User, requestPasswordParams.SecurityItemId);
affiliateUser = accountMgrForUser.GetAffiliateById(requestPasswordParams.AffiliateId);
if (requestPasswordParams.IsValid(securityItemUser, affiliateUser))
{
validRequestPasswordParams = true;
validSessionRequired = false;
break;
}
else
{
SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. Email: " + requestPasswordParams.EmailAddress + ". SecurityItemId: " + SysId.ToString(requestPasswordParams.SecurityItemId) + ". AffiliateId: " + SysId.ToString(requestPasswordParams.AffiliateId));
if (securityItemUser != null) securityItemUser.Dispose(); securityItemUser = null;
if (affiliateUser != null) affiliateUser.Dispose(); affiliateUser = null;
sessionContextForUser = null;
userContextForUser = null;
}
}
}
}
// User must have a valid session.
// User must have a valid session if security item and affiliate not idenfied via the 'Request Password' paramaters.
if (validSessionRequired && (securityItemUser == null || affiliateUser == null) && !ValidUserSession)
return Json(responseData.SetSessionExpired(messageTitle, Localiser["security.msg.warn.sessionExpired"]));
// Retrieve user details if not previously populated.
if (securityItemUser == null && SessionData_Portal != null)
securityItemUser = SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, SessionData_Portal.User.SecurityItemId);
if (securityItemUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve security item details."));
if (affiliateUser == null && SessionData_Portal != null)
affiliateUser = AccountMgr.GetAffiliateById(SessionData_Portal.User.AffiliateId);
if (affiliateUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve affiliate details."));
// Validate password data.
model.ValidateChangePasswordData(securityItemUser, affiliateUser, responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Note old password.
String oldPasswordHashed = securityItemUser.PasswordHash;
// Store password.
securityItemUser.PasswordHash = SbmPasswordHelper.GetPasswordHash(securityItemUser, model.Password);
securityItemUser.PasswordChangedAt = DateTime.Now;
// Remove new password from history if present.
for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++)
// User specific Consoles and Managers if User Context specified.
using (SaSecurityConsole securityConsoleForUser = userContextForUser != null ? App.CreateSecurityConsole(userContextForUser) : null)
using (SbmAccountMgr accountMgrForUser = userContextForUser != null ? App.System.CreateAccountMgr(userContextForUser) : null)
{
// Compare history password to new value.
if (SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password, securityItemUser.PasswordHistory[passwordHistoryIdx]))
SaSecurityConsole securityConsole = (securityConsoleForUser ?? SecurityConsole);
SbmAccountMgr accountMgr = (accountMgrForUser ?? AccountMgr);
// Retrieve user details if not previously populated.
if (securityItemUser == null && SessionData_Portal != null)
securityItemUser = (securityConsole.GetSecurityItemById(SaSecurity.ItemType.User, SessionData_Portal.User.SecurityItemId));
if (securityItemUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve security item details."));
if (affiliateUser == null && SessionData_Portal != null)
affiliateUser = accountMgr.GetAffiliateById(SessionData_Portal.User.AffiliateId);
if (affiliateUser == null)
return Json(responseData.SetControlError(nameof(model.Password), "System error - failed to retrieve affiliate details."));
// Validate password data.
model.ValidateChangePasswordData(securityItemUser, affiliateUser, responseData);
if (responseData.HasControlErrors())
return Json(responseData);
// Note old password.
String oldPasswordHashed = securityItemUser.PasswordHash;
// Store password.
securityItemUser.PasswordHash = SbmPasswordHelper.GetPasswordHash(securityItemUser, model.Password);
securityItemUser.PasswordChangedAt = DateTime.Now;
// Remove new password from history if present.
for (int passwordHistoryIdx = 0; passwordHistoryIdx < securityItemUser.PasswordHistory.Count; passwordHistoryIdx++)
{
// New password found in history - remove it.
securityItemUser.PasswordHistory.RemoveAt(passwordHistoryIdx);
passwordHistoryIdx--;
// Compare history password to new value.
if (SbmPasswordHelper.VerifyHashedPassword(securityItemUser, model.Password, securityItemUser.PasswordHistory[passwordHistoryIdx]))
{
// New password found in history - remove it.
securityItemUser.PasswordHistory.RemoveAt(passwordHistoryIdx);
passwordHistoryIdx--;
}
}
securityItemUser.PasswordHistory.Remove(oldPasswordHashed);
// Add the old password at the start of the history list and validate history length.
securityItemUser.PasswordHistory.Add(oldPasswordHashed);
while (securityItemUser.PasswordHistory.Count > 10)
securityItemUser.PasswordHistory.RemoveAt(securityItemUser.PasswordHistory.Count - 1);
if (!securityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to change password for " + securityItemUser.EmailAddress + ": " + securityConsole.ErrorStateMessage);
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
}
SaLogger.Info(fn + " Password changed for " + securityItemUser.EmailAddress, true);
}
securityItemUser.PasswordHistory.Remove(oldPasswordHashed);
// Add the old password at the start of the history list and validate history length.
securityItemUser.PasswordHistory.Add(oldPasswordHashed);
while (securityItemUser.PasswordHistory.Count > 10)
securityItemUser.PasswordHistory.RemoveAt(securityItemUser.PasswordHistory.Count - 1);
if (!SecurityConsole.UpdateSecurityItem(securityItemUser, DbUpdateInfo))
{
SaLogger.Warn(fn + " Failed to change password for " + securityItemUser.EmailAddress + ": " + AccountMgr.ErrorStateMessage);
return Json(responseData.SetControlError(nameof(model.Password), Localiser["security.msg.change.password.failed"]));
}
SaLogger.Info(fn + " Password changed for " + securityItemUser.EmailAddress, true);
// Cleanup. NB The Security Item and/or Affiliate aren't disposed when the method
// returns above but these objects shouldn't be carrying any disposable resources.
if (securityItemUser != null) securityItemUser.Dispose(); securityItemUser = null;
if (affiliateUser != null) affiliateUser.Dispose(); affiliateUser = null;
sessionContextForUser = null;
userContextForUser = null;
// Construct response.
responseData.Success = true;
@@ -350,10 +390,10 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
}
// Ajax request.
[HttpPost]
[Route("Security/Ajax/RequestNewPassword")]
public ActionResult Ajax_RequestNewPassword(Model_Security model)
[Route("Security/Ajax/RequestPassword")]
public ActionResult Ajax_RequestPassword(Model_Security model)
{
String fn = GetType().Name + ".Ajax_RequestNewPassword";
String fn = GetType().Name + ".Ajax_RequestPassword";
AjaxResponse_RequestPassword responseData = new AjaxResponse_RequestPassword(model);
String messageTitle = Localiser["security.caption.request.password"];
@@ -372,15 +412,15 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
// Get user security item and affiliate.
using (SaSecurityConsole securityConsole = App.CreateSecurityConsole(userContext))
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
{
using (SaSecurityItem securityItemUser = securityConsole.GetUserByEmail(model.EmailAddress))
using (SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(model.EmailAddress))
{
if (securityItemUser != null)
{
using (SbmAccountMgr accountMgr = App.System.CreateAccountMgr(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{
using (SbmAffiliate affiliateUser = accountMgr.GetAffiliateByUserId(securityItemUser.Id))
using (SbmAffiliate affiliateUser = accountMgrForUser.GetAffiliateByUserId(securityItemUser.Id))
{
if (affiliateUser != null)
{
@@ -431,9 +471,9 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
//-------------------------------------------------------------------
// Password request link.
private static String ParamName_RequestPasswordEncrypted { get; } = "rpe";
private static String ParamName_EmailAddress { get; } = "ema";
private static String ParamName_SecurityItemId { get; } = "sei";
private static String ParamName_AffiliateId { get; } = "afi";
private static String ParamName_EmailAddress { get; } = "ema";
private static String ParamName_ExpiresAt { get; } = "exp";
private static String ParamName_Token { get; } = "tok";
// NB IV value is generated from the key and fixed so that it doesn't change when the application restarts.
@@ -444,9 +484,9 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
private String GenerateRequestPasswordLink(SysId securityItemId, SysId affiliateId, String emailAddress, String requestPasswordToken)
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add(ParamName_EmailAddress, emailAddress);
parameters.Add(ParamName_SecurityItemId, SysId.ToString(securityItemId));
parameters.Add(ParamName_AffiliateId, SysId.ToString(affiliateId));
parameters.Add(ParamName_EmailAddress, emailAddress);
parameters.Add(ParamName_ExpiresAt, DateUtil.Format(DateTime.Now.AddMinutes(GetRequestPasswordEmailLinkExpiresMinutes()), DateUtil.Format_XmlDateTime));
parameters.Add(ParamName_Token, requestPasswordToken);
String link =
@@ -463,34 +503,34 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
}
private class RequestPasswordParams
{
public String EmailAddress { get; set; }
public SysId SecurityItemId { get; set; }
public SysId AffiliateId { get; set; }
public String EmailAddress { get; set; }
public DateTime ExpiresAt { get; set; }
public String Token { get; set; }
/// <summary>Retrieve the list of valid parameters in printable format [Name: Value].</summary>
public List<String> GetValidParams()
{
List<String> values = new List<String>();
if (!StringUtil.IsEmpty(EmailAddress))
values.Add("Email: " + EmailAddress);
if (SysId.IsValid(SecurityItemId))
values.Add("SecurityItemId: " + SysId.ToString(SecurityItemId));
if (SysId.IsValid(AffiliateId))
values.Add("AffiliateId: " + SysId.ToString(AffiliateId));
if (!StringUtil.IsEmpty(EmailAddress))
values.Add("Email: " + EmailAddress);
if (DateUtil.IsValid(ExpiresAt))
values.Add("Expires: " + DateUtil.FormatXmlDateTime(ExpiresAt));
if (!StringUtil.IsEmpty(Token))
values.Add("Token: " + Token);
return values;
}
/// <summary>Verifiy that the account Id and email are populated and the data hasn't expired.</summary>
/// <summary>Verifiy that the email and account Ids are populated and the data hasn't expired.</summary>
public bool IsValid()
{
return
!StringUtil.IsEmpty(EmailAddress) &&
SysId.IsValid(SecurityItemId) &&
SysId.IsValid(AffiliateId) &&
!StringUtil.IsEmpty(EmailAddress) &&
DateUtil.IsValid(ExpiresAt) && ExpiresAt >= DateTime.Now;
}
/// <summary>Verify that the data is valid and the account details match.</summary>
@@ -498,10 +538,11 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
{
return
IsValid() &&
affiliateUser != null &&
securityItemUser.EmailAddress.EqualsCI(EmailAddress) &&
securityItemUser != null &&
securityItemUser.Id.Equals(SecurityItemId) &&
affiliateUser.Id.Equals(AffiliateId) &&
securityItemUser.EmailAddress.EqualsCI(EmailAddress);
affiliateUser != null &&
affiliateUser.Id.Equals(AffiliateId);
}
}
private RequestPasswordParams ExtractRequestPasswordLinkParams(String encryptedParams)
@@ -510,9 +551,9 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
if (!StringUtil.IsEmpty(encryptedParams))
{
NameValueCollection linkParams = DecryptParameters(encryptedParams, Base64IV_RequestPassword, Base64Key_RequestPassword);
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
requestPasswordParams.SecurityItemId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_SecurityItemId)));
requestPasswordParams.AffiliateId = new SysId(StringUtil.ToInt(linkParams.Get(ParamName_AffiliateId)));
requestPasswordParams.EmailAddress = linkParams.Get(ParamName_EmailAddress);
requestPasswordParams.ExpiresAt = DateUtil.ParseXmlDateTime(linkParams.Get(ParamName_ExpiresAt));
requestPasswordParams.Token = linkParams.Get(ParamName_Token);
}
@@ -2,8 +2,11 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Helpers;
using Sarand.BusinessMgr.Net.Core.Web.Portal.Models;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Mgr;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Bus;
using Sarand.Net.Standard.Base.Security;
@@ -71,24 +74,43 @@ namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Controllers
RequestPasswordParams requestPasswordParams = ExtractRequestPasswordLinkParams(encryptedParams);
if (requestPasswordParams.IsValid())
{
String logPrefix = fn + " 'Request Password' parameters supplied but ";
String logSuffix = requestPasswordParams.GetValidParams().Concat("", " ", ".");
using (SaSecurityItem securityItemUser = SecurityConsole.GetSecurityItemById(SaSecurity.ItemType.User, requestPasswordParams.SecurityItemId))
using (SbmAffiliate userAccount = AccountMgr.GetAffiliateById(requestPasswordParams.AffiliateId))
// User may be defined on any one of the BusinessMgr databases - need to find out which.
// Identify session contexts with a BusMgr database that hosts the specified email address.
List<ushort> sessionContextIdxs = SbmSessionContextHelper_Web.GetSessionContextIdxsForUsersBusMgrDatabase(requestPasswordParams.EmailAddress);
foreach (ushort sessionContextIdx in sessionContextIdxs)
{
if (securityItemUser != null && userAccount != null)
// Consoles and Managers must be associated with the specific context.
SbmSessionContext sessionContext = SbmSessionContextHelper_Web.GetSessionContext(sessionContextIdx);
SbmUserContext_Web userContext = new SbmUserContext_Web(sessionContext);
using (SaSecurityConsole securityConsoleForUser = App.CreateSecurityConsole(userContext))
using (SbmAccountMgr accountMgrForUser = App.System.CreateAccountMgr(userContext))
{
if (userAccount.IsStatusActive)
using (SaSecurityItem securityItemUser = securityConsoleForUser.GetUserByEmail(requestPasswordParams.EmailAddress))
using (SbmAffiliate affiliateUser = accountMgrForUser.GetAffiliateById(requestPasswordParams.AffiliateId))
{
if (requestPasswordParams.IsValid(securityItemUser, userAccount))
if (securityItemUser != null && affiliateUser != null)
{
model.rpe = encryptedParams;
validSessionRequired = false;
if (securityItemUser.Id.Equals(requestPasswordParams.SecurityItemId) && affiliateUser.UserId.Equals(securityItemUser.Id))
{
if (affiliateUser.IsStatusCurrent)
{
if (requestPasswordParams.IsValid(securityItemUser, affiliateUser))
{
model.rpe = encryptedParams;
validSessionRequired = false;
break;
}
else SaLogger.Warn(logPrefix + "Security Item and Affiliate are incompatible with parameters. " + logSuffix);
}
else SaLogger.Warn(logPrefix + "Affiliate is not active. " + logSuffix);
}
else SaLogger.Warn(logPrefix + "Security Item and Affiliate are inconsistent. " + logSuffix);
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but invalid. " + logSuffix);
else SaLogger.Warn(logPrefix + "Security Item or Affiliate not found. " + logSuffix);
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but account is not active. " + logSuffix);
}
else SaLogger.Warn(fn + " 'Request Password' parameters supplied but security item or affiliate not found. " + logSuffix);
}
}
}
@@ -0,0 +1,104 @@
using Sarand.BusinessMgr.Net.Core.Web.App;
using Sarand.BusinessMgr.Net.Core.Web.Controllers;
using Sarand.BusinessMgr.Net.Standard.Base.App;
using Sarand.BusinessMgr.Net.Standard.Base.Bus;
using Sarand.BusinessMgr.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.App;
using Sarand.Net.Standard.Base.Core;
using Sarand.Net.Standard.Base.Helpers;
using Sarand.Net.Standard.Base.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sarand.BusinessMgr.Net.Core.Web.Portal.Models
{
//=======================================================================
public class Model_Contact : SbmModel_Portal
{
//-------------------------------------------------------------------
// Construction.
public Model_Contact(SbmLocaliser localiser) :
base(localiser)
{
AdditionalFiles_JS.Add("js/sbm-contact.js");
}
//-------------------------------------------------------------------
// Filter properties.
public class FilterData
{
public String AffiliateSearch { get; set; }
public String AffiliateType { get; set; }
}
public FilterData Filter { get; } = new FilterData();
public Sbm.AffiliateType GetFilterAffiliateType()
{
return (Sbm.AffiliateType)Internals.AffiliateTypeCodes.GetTypeForCode(Filter.AffiliateType);
}
//-------------------------------------------------------------------
// Affiliate properties.
public String AffiliateId { get; set; }
public String AffiliateType{ get; set; }
public Sbm.AffiliateType GetAffiliateType()
{
return (Sbm.AffiliateType)Internals.AffiliateTypeCodes.GetTypeForCode(AffiliateType);
}
public String AffiliateName { get; set; }
// Common properties.
public String AffiliateNotes { get; set; }
public String AffiliateStatus { get; set; }
public SaStatus GetAffiliateStatus()
{
return SacsSystem.GetStatusForCode(AffiliateStatus);
}
//-------------------------------------------------------------------
// Validation.
//-------------------------------------------------------------------
// Affiliate validation.
public bool ValidateAffiliateData(SbmController_Base.AjaxResponse_Data responseData)
{
// Affiliate Type.
if (AffiliateType != null)
{
if (StringUtil.IsEmpty(AffiliateType))
responseData.SetControlError(nameof(AffiliateType), Localiser["msg.validation.mandatory.value"]);
}
// Affiliate Name.
if (AffiliateName != null)
{
responseData.SetControlValue(nameof(AffiliateName), AffiliateName);
if (StringUtil.IsEmpty(AffiliateName))
responseData.SetControlError(nameof(AffiliateName), Localiser["msg.validation.mandatory.value"]);
if (StringUtil.GetLength(AffiliateName) > GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_Name))
responseData.SetControlError(nameof(AffiliateName), Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_Name)]);
}
// Affiliate Notes.
if (AffiliateNotes != null)
{
responseData.SetControlValue(nameof(AffiliateNotes), AffiliateNotes);
if (!StringUtil.IsEmpty(AffiliateNotes) && StringUtil.GetLength(AffiliateNotes) > GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_Notes))
responseData.SetControlError(nameof(AffiliateNotes), Localiser["msg.validation.maximum.length", GetControlMaxLength(SbmDbDfn.ColumnIdx.Affiliate_Notes)]);
}
// Affiliate status.
if (AffiliateStatus != null)
{
if (StringUtil.IsEmpty(AffiliateStatus))
responseData.SetControlError(nameof(AffiliateStatus), Localiser["msg.validation.mandatory.value"]);
else if (!SbmAffiliate.ValidStatuses.Contains(GetAffiliateStatus()))
responseData.SetControlError(nameof(AffiliateStatus), Localiser["msg.validation.invalid.value"]);
}
return !responseData.HasControlErrors();
}
//-------------------------------------------------------------------
}
//=======================================================================
}