Contacts page.
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
Reference in New Issue
Block a user