diff --git a/SaBusMgrStandardBase/Base/App/Sbm-Version.cs b/SaBusMgrStandardBase/Base/App/Sbm-Version.cs index b816942..e75622b 100644 --- a/SaBusMgrStandardBase/Base/App/Sbm-Version.cs +++ b/SaBusMgrStandardBase/Base/App/Sbm-Version.cs @@ -15,7 +15,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.App //------------------------------------------------------------------- public static class Version { - private static String version { get; } = "3.0.0.2"; + private static String version { get; } = "3.0.0.3"; // Retrieve version. public static String GetFullVersion() { return version; } public static String GetAppVersion() @@ -40,6 +40,8 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.App // 3.0.0 Jul-2021 Initial demo test version. // 02-Feb-25 Initial live deployment. // 3.0.0.1 08-Feb-25 Demo repository registration. + // 3.0.0.2 08-Feb-25 Production SMTP config. + // 3.0.0.3 10-Feb-25 Osie feedback #1. Control Repository Schema, Logs. //------------------------------------------------------------------- } //======================================================================= diff --git a/SaBusMgrStandardBase/Base/App/Sbm.cs b/SaBusMgrStandardBase/Base/App/Sbm.cs index 90041d5..814380c 100644 --- a/SaBusMgrStandardBase/Base/App/Sbm.cs +++ b/SaBusMgrStandardBase/Base/App/Sbm.cs @@ -113,6 +113,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.App { WebControl, WebPortal, + WebDemo, } public enum InstanceType { @@ -125,6 +126,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.App { Unknown, Control, + BusMgr, Template, Demo, } diff --git a/SaBusMgrStandardBase/Base/App/SbmSessionContext.cs b/SaBusMgrStandardBase/Base/App/SbmSessionContext.cs index 07602ad..6da51d9 100644 --- a/SaBusMgrStandardBase/Base/App/SbmSessionContext.cs +++ b/SaBusMgrStandardBase/Base/App/SbmSessionContext.cs @@ -19,6 +19,8 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.App // Properties. public Sbm.Application Application { get; private set; } + public bool IsDemoRepository() { return Application == Sbm.Application.WebDemo; } + //------------------------------------------------------------------- } //======================================================================= diff --git a/SaBusMgrStandardBase/Base/Consoles/SbmSessionConsole.cs b/SaBusMgrStandardBase/Base/Consoles/SbmSessionConsole.cs index 8d58f4e..f76609e 100644 --- a/SaBusMgrStandardBase/Base/Consoles/SbmSessionConsole.cs +++ b/SaBusMgrStandardBase/Base/Consoles/SbmSessionConsole.cs @@ -112,8 +112,8 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.Consoles private SbmInternals Internals { get { return mbr.InternalsSupplied; } } public ISbmUserOrganisationContext UserContext { get { return Internals.UserContext; } } public SbmSessionContext SessionContext { get { return Internals.SessionContext; } } - public SbmInstanceConfig InstanceConfig { get { if (instanceConfig == null) instanceConfig = SbmGlobals.Application.GetInstanceConfig(SessionContext); return instanceConfig; } } - public SbmOrganisationConfig OrganisationConfig { get { if (organisationConfig == null) organisationConfig = SbmGlobals.Application.GetOrganisationConfig(UserContext); return organisationConfig; } } + public SbmInstanceConfig InstanceConfig { get { if (instanceConfig == null) { instanceConfig = SbmGlobals.Application.GetInstanceConfig(SessionContext); } return instanceConfig; } } + public SbmOrganisationConfig OrganisationConfig { get { if (organisationConfig == null) { organisationConfig = SbmGlobals.Application.GetOrganisationConfig(UserContext); } return organisationConfig; } } //------------------------------------------------------------------- // C r e a t e C o n s o l e @@ -224,6 +224,17 @@ namespace Sarand.BusinessMgr.Net.Standard.Base.Consoles return false; } + //------------------------------------------------------------------- + // Demo Repository restrictions. + + /// + /// Demo application should not display Individual Contacts for User Accounts other than that logged in. + /// + public bool HideOtherUserContacts() + { + return SessionContext.IsDemoRepository(); + } + //------------------------------------------------------------------- // Application Configuration. - AllowOption. public virtual bool AllowOption(Sbm.ConfigOption option) diff --git a/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Affiliate.cs b/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Affiliate.cs index 0459b02..5eb0db7 100644 --- a/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Affiliate.cs +++ b/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Affiliate.cs @@ -155,7 +155,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Create Affiliate. + // Create Item. public override SbmAffiliate CreateAffiliate(Sbm.AffiliateType affiliateType) { return new SbmAffiliate_Dbas(null, affiliateType, 0); @@ -169,7 +169,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Get Affiliate. + // Get Item. public override SbmAffiliate GetAffiliate(SbmAffiliate.Params prm) { return GetAffiliate(GetAffiliateQueryFilter(prm).Concat(" AND ", "(", ")")); @@ -206,6 +206,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- + // Affiliate properties. public override String GetAffiliateName(SysId affiliateId) { ClearErrorState(); @@ -280,7 +281,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Validate item properties. + // Validate Item properties. public override bool IsValidAffiliateData(SbmAffiliate.Data data, SbmAffiliate.ErrField errField) { ClearErrorState(); @@ -666,16 +667,27 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr public override List GetAffiliateQueryFilter(SbmAffiliate.Params prm) { List filter = new List(); - - // Item Id. String colAffiliate_Id = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Id, aliasAffiliate); + String colAffiliate_Type = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Type, aliasAffiliate); + String colAffiliate_UserId = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_UserId, aliasAffiliate); + + //--------------------------------------------------------------- + // Demo application restrictions - when user logged in. + if (SysId.IsValid(UserContext.UserAffiliateId) && SessionConsole.HideOtherUserContacts()) + { + // Exclude Individual contacts with User Id other than the logged in user. + // NB Keep logic in line with corresponding Affiliate method (SbmAccountMgr_Dbas.GetAssociationQueryFilter). + filter.Add($"{colAffiliate_Id} Not In (Select Id From {SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Affiliate)} Where Id!={UserContext.UserAffiliateId} And Type={(int)Sbm.AffiliateType.Individual} And UserId>0)"); + } + + //--------------------------------------------------------------- + // Item Id. if (prm.IdsIncluded.HasValidIds()) filter.Add($"{colAffiliate_Id} IN ({prm.IdsIncluded.Concat(",")})"); if (prm.IdsExcluded.HasValidIds()) filter.Add($"{colAffiliate_Id} NOT IN ({prm.IdsExcluded.Concat(",")})"); // Type. - String colAffiliate_Type = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_Type, aliasAffiliate); // Affiliate type - Individual. if (prm.AffiliateType == Sbm.AffiliateType.AnyOrganisation) filter.Add($"{colAffiliate_Type} Not In ({(int)Sbm.AffiliateType.Individual}, {(int)Sbm.AffiliateType.ContactGroup})"); @@ -687,9 +699,11 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr filter.Add($"{colAffiliate_Type}={(int)prm.AffiliateType}"); // Parent Id. - String colAffiliate_AffIdParent = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_AffIdParent, aliasAffiliate); if (SysId.IsValid(prm.AffiliateIdParent)) + { + String colAffiliate_AffIdParent = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_AffIdParent, aliasAffiliate); filter.Add($"{colAffiliate_AffIdParent}={SysId.ToString(prm.AffiliateIdParent)}"); + } //--------------------------------------------------------------- // Common columns. @@ -725,7 +739,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr searchValueFilter.Add(colAffiliate_Notes + " LIKE '%" + searchValue + "%'"); searchFilter.Add(searchValueFilter.Concat(" OR ", "(", ")")); } - filter.AddRange(searchFilter); + if (searchFilter.Any()) filter.AddRange(searchFilter); } //--------------------------------------------------------------- @@ -894,7 +908,6 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr //--------------------------------------------------------------- // User Id. - String colAffiliate_UserId = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Affiliate_UserId, aliasAffiliate); if (SysId.IsValid(prm.UserId)) filter.Add($"{colAffiliate_UserId}={SysId.ToString(prm.UserId)}"); diff --git a/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Association.cs b/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Association.cs index 97dfcef..afd5cbd 100644 --- a/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Association.cs +++ b/SaBusMgrStandardDbas/Dbas/Mgr/SbmAccountMgr_Dbas-Association.cs @@ -40,7 +40,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Get Association. + // Get Item. public override SbmAssociation GetAssociation(SbmAssociation.Params prm) { return GetAssociation(GetAssociationQueryFilter(prm).Concat(" AND ", "(", ")")); @@ -77,6 +77,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- + // Item properties. public override SysId GetAssociationAffIdTarget(SysId associationId) { ClearErrorState(); @@ -127,7 +128,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Validate Association. + // Validate Item. public override bool IsValidAssociationData(SbmAssociation.Data data, SbmAssociation.ErrField errField) { ClearErrorState(); @@ -145,7 +146,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Insert Association. + // Insert Item. public override bool InsertAssociation(SbmAssociation association, DbUpdateInfo dbUpdateInfo) { ClearErrorState(); @@ -175,7 +176,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Update Association. + // Update Item. public override bool UpdateAssociation(SbmAssociation association, DbUpdateInfo dbUpdateInfo) { ClearErrorState(); @@ -213,7 +214,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Delete Association. + // Delete Item. public override bool AssociationCanBeDeleted(SbmAssociation association) { ClearErrorState(); @@ -511,7 +512,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr } //------------------------------------------------------------------- - // Column definitions. + // Item Column definitions. private static readonly String aliasAssociation = "aAssoc"; // Association Owner contact. private static string aliasAssociation_Affiliate_Owner = "Asn_AffOwn"; @@ -556,7 +557,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr col.MaxLength = (int)Internals.GetColTextLen(dbCol); } //------------------------------------------------------------------- - // Getting prmAssociation column definition. + // Item column definition. public override ColumnDfn GetAssociationColumnDfn(SbmAssociation.Column column, string caption = "", int width = 0) { ColumnDfn columnDfn = new ColumnDfn((int)column, caption, width); @@ -1120,10 +1121,21 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr public override List GetAssociationQueryFilter(SbmAssociation.Params prm) { List filter = new List(); + String colAssociation_Id = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Id, aliasAssociation); + String colAssociation_AffIdOwner = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdOwner, aliasAssociation); + String colAssociation_AffIdTarget = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdTarget, aliasAssociation); + + //--------------------------------------------------------------- + // Demo application restrictions - when user logged in. + if (SysId.IsValid(UserContext.UserAffiliateId) && SessionConsole.HideOtherUserContacts()) + { + // Exclude Individual contacts with User Id other than the logged in user. + // NB Keep logic in line with corresponding Affiliate method (SbmAccountMgr_Dbas.GetAffiliateQueryFilter). + filter.Add($"{colAssociation_AffIdTarget} Not In (Select Id From {SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Affiliate)} Where Id!={UserContext.UserAffiliateId} And Type={(int)Sbm.AffiliateType.Individual} And UserId>0)"); + } //--------------------------------------------------------------- // Association Id. - String colAssociation_Id = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_Id, aliasAssociation); if (prm.IdsIncluded.HasValidIds()) filter.Add($"{colAssociation_Id} IN ({prm.IdsIncluded.Concat(",")})"); if (prm.IdsExcluded.HasValidIds()) @@ -1138,12 +1150,10 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr //--------------------------------------------------------------- // Owner affiliate. - String colAssociation_AffIdOwner = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdOwner, aliasAssociation); if (SysId.IsValid(prm.AffiliateIdOwner)) filter.Add($"{colAssociation_AffIdOwner}={prm.AffiliateIdOwner}"); // Target Affiliate. - String colAssociation_AffIdTarget = SbmDbDfn.GetColumnNameQual(SbmDbDfn.ColumnIdx.Association_AffIdTarget, aliasAssociation); if (SysId.IsValid(prm.AffiliateIdTarget)) filter.Add($"{colAssociation_AffIdTarget}={prm.AffiliateIdTarget}"); @@ -1151,7 +1161,7 @@ namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr // Contact Group. if (SysId.IsValid(prm.AffiliateIdContactGroup)) { - //Association must also be a member of this contact group. + // Association must also be a member of this contact group. String aliasAssocContactGroup = "aAssConGrp"; DbQuery queryAssocContactGroup = new DbQuery(Database.DbmsType); queryAssocContactGroup.Tables.Add(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Association), aliasAssocContactGroup); diff --git a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Database_Tester.cs b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Database_Tester.cs index a8be453..43069f8 100644 --- a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Database_Tester.cs +++ b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Database_Tester.cs @@ -28,7 +28,7 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App { // Session configuration. string repositoryContext = "Mimo"; - SbmSessionContext sessionContext = CreateCoreInstanceConsole(repositoryContext); + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); Assert.IsNotNull(sessionContext); SbmInternals internals = new SbmInternals(GetSessionData(sessionContext, repositoryContext)); disposables.Add(internals); @@ -55,7 +55,7 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App { // Session configuration. string repositoryContext = "Mimo"; - SbmSessionContext sessionContext = CreateCoreInstanceConsole(repositoryContext); + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); Assert.IsNotNull(sessionContext); SbmInternals internals = new SbmInternals(GetSessionData(sessionContext, repositoryContext)); disposables.Add(internals); diff --git a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_DemoRepository_Tester.cs b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_DemoRepository_Tester.cs new file mode 100644 index 0000000..3b2a9d5 --- /dev/null +++ b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_DemoRepository_Tester.cs @@ -0,0 +1,78 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; +using Sarand.BusinessMgr.Net.Core.Web.Components; +using Sarand.BusinessMgr.Net.Standard.Base.App; +using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control; +using Sarand.BusinessMgr.Net.Standard.Base.Mgr.Control; +using Sarand.BusinessMgr.Web.Portal.App; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Dbas; +using Sarand.Net.Standard.Base.Security; +using Sarand.Net.Standard.Dbas.Base; + +namespace Sarand.BusinessMgr.Test.Web.Portal.App +{ + //======================================================================= + [TestClass] + public class SbmApplication_DemoRepository_Tester : SbmApplication_Tester_Base + { + //------------------------------------------------------------------- + [TestMethod] + public void Test_SessionData_Demo() + { + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposables = new DisposableCollection()) + { + // Demo Session configuration. + string repositoryContext = Sbm.RepositoryContext_Demo; + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); + Assert.IsNotNull(sessionContext); + + // Session data. + SbmSessionData_Portal sessionData = new SbmSessionData_Portal(sessionContext, repositoryContext, null, null, null, null); + Assert.IsNotNull(sessionData); + Assert.IsTrue(sessionData.SessionContext.IsDemoRepository()); + + // Serialise data. + string sessionDataJson = JsonConvert.SerializeObject(sessionData, SbmController_Web.SessionDataJsonSerializerSettings); + Assert.IsNotNull(sessionDataJson); + + // Deserialise data. + SbmSessionData_Portal sessionDataDeserialized = JsonConvert.DeserializeObject(sessionDataJson, SbmController_Web.SessionDataJsonDeserializerSettings); + Assert.IsNotNull(sessionDataDeserialized); + Assert.IsTrue(sessionDataDeserialized.SessionContext.IsDemoRepository()); + } + } + + //------------------------------------------------------------------- + [TestMethod] + public void Test_SessionData_NonDemo() + { + // Record disposable items as they are created so all can be disposed when needed. + using (DisposableCollection disposables = new DisposableCollection()) + { + // Non-Demo Session configuration. + string repositoryContext = "Mimo"; + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); + Assert.IsNotNull(sessionContext); + + // Session data. + SbmSessionData_Portal sessionData = new SbmSessionData_Portal(sessionContext, repositoryContext, null, null, null, null); + Assert.IsNotNull(sessionData); + Assert.IsFalse(sessionData.SessionContext.IsDemoRepository()); + + // Serialise data. + string sessionDataJson = JsonConvert.SerializeObject(sessionData, SbmController_Web.SessionDataJsonSerializerSettings); + Assert.IsNotNull(sessionDataJson); + + // Deserialise data. + SbmSessionData_Portal sessionDataDeserialized = JsonConvert.DeserializeObject(sessionDataJson, SbmController_Web.SessionDataJsonDeserializerSettings); + Assert.IsNotNull(sessionDataDeserialized); + Assert.IsFalse(sessionDataDeserialized.SessionContext.IsDemoRepository()); + } + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_SessionData_Tester.cs b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_SessionData_Tester.cs index c18ce1c..971c3d8 100644 --- a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_SessionData_Tester.cs +++ b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_SessionData_Tester.cs @@ -39,12 +39,16 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App { // Session configuration. string repositoryContext = "Mimo"; - SbmSessionContext sessionContext = CreateCoreInstanceConsole(repositoryContext); + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); Assert.IsNotNull(sessionContext); ISacsDatabase busMgrDatabase = AppPortal.GetBusMgrDatabase(sessionContext); + // Session data. + SbmSessionData_Portal sessionData = new SbmSessionData_Portal(sessionContext, repositoryContext, null, null, null, null); + Assert.IsNotNull(sessionData); + // Internals. - SbmInternals internals = new SbmInternals(GetSessionData(sessionContext, repositoryContext)); + SbmInternals internals = new SbmInternals(sessionData); disposables.Add(internals); SaSecurityConsole securityConsole = internals.SecurityConsole; Assert.IsNotNull(securityConsole); @@ -76,9 +80,8 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App Assert.IsNotNull(affiliateOrganisation); - // Populate User Session. - SbmSessionData_Portal sessionData = new SbmSessionData_Portal(sessionContext, repositoryContext, securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation); - Assert.IsNotNull(sessionData); + // Populate Session data. + sessionData.Refresh(securityItemUser, affiliateUser, associationOrganisation, affiliateOrganisation); // Validate user session. Assert.IsNotNull(sessionData.User); @@ -167,7 +170,7 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App // Session configuration. string repositoryContext = "Mimo"; - SbmSessionContext sessionContext = CreateCoreInstanceConsole(repositoryContext); + SbmSessionContext sessionContext = GetCoreSessionContext(repositoryContext); Assert.IsNotNull(sessionContext); ISacsDatabase busMgrDatabase = AppPortal.GetBusMgrDatabase(sessionContext); diff --git a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Tester_Base.cs b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Tester_Base.cs index 0655f25..5520a6f 100644 --- a/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Tester_Base.cs +++ b/SaBusMgrTest_Portal/Web/Portal/App/SbmApplication_Tester_Base.cs @@ -70,7 +70,7 @@ namespace Sarand.BusinessMgr.Test.Web.Portal.App //------------------------------------------------------------------- // Session Context. - protected SbmSessionContext CreateCoreInstanceConsole(String instanceContext) + protected SbmSessionContext GetCoreSessionContext(String instanceContext) { return AppPortal.GetControlSessionContextByRepositoryContext(instanceContext); } diff --git a/SaBusinessMgrCoreWebControl/Control/App/SbmSessionData_Control.cs b/SaBusinessMgrCoreWebControl/Control/App/SbmSessionData_Control.cs index 9caede9..62ba912 100644 --- a/SaBusinessMgrCoreWebControl/Control/App/SbmSessionData_Control.cs +++ b/SaBusinessMgrCoreWebControl/Control/App/SbmSessionData_Control.cs @@ -123,6 +123,31 @@ namespace Sarand.BusinessMgr.Web.Control.App } public UserProfileData Profile { get; protected set; } = new UserProfileData(); + //------------------------------------------------------------------- + // System. + public class SystemData + { + // Databases. + public class DatabaseData + { + } + public DatabaseData Database { get; private set; } = new DatabaseData(); + + // Logs. + public class LogsData + { + public class FilterData + { + public String Folder { get; set; } + public String Year { get; set; } + public String Month { get; set; } + } + public FilterData Filter { get; private set; } = new FilterData(); + } + public LogsData Logs { get; private set; } = new LogsData(); + } + public SystemData System { get; private set; } = new SystemData(); + //------------------------------------------------------------------- // Control application encryption IV value - for consistent encryption during session. public String Base64IV_ControlApp { get; private set; } = SacsEncryptionHelper.InitSymmetricEncryptionIV(SbmController_Control.Base64Key_ControlApp); diff --git a/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController-Ajax.cs b/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController-Ajax.cs similarity index 91% rename from SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController-Ajax.cs rename to SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController-Ajax.cs index 073d9b0..e71d62e 100644 --- a/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController-Ajax.cs +++ b/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController-Ajax.cs @@ -17,7 +17,7 @@ using System.Linq; namespace Sarand.BusinessMgr.Web.Control.Controllers.Instance { //======================================================================= - partial class CoreDatabaseController + partial class RepositoryDatabaseController { //------------------------------------------------------------------- // Definitions. @@ -35,21 +35,21 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.Instance //------------------------------------------------------------------- // Get Core Database Table list ajax request. //------------------------------------------------------------------- - private class AjaxResponse_CoreDatabaseTableList : AjaxResponse_Data + private class AjaxResponse_RepositoryTableList : AjaxResponse_Data { // Construction. - public AjaxResponse_CoreDatabaseTableList(SbmModel_Control model) : base(model) { } - // CoreDatabase list. + public AjaxResponse_RepositoryTableList(SbmModel_Control model) : base(model) { } + // Table list. public List Tables { get; } = new List(); } //------------------------------------------------------------------- [HttpPost] - [Route("Instance/CoreDatabase/Ajax/GetTableList")] - [Route("Instance/CoreDatabase/Ajax/GetTables")] - public IActionResult Ajax_GetTableList(Model_CoreDatabase model) + [Route("Instance/Repository/Ajax/GetTableList")] + [Route("Instance/Repository/Ajax/GetTables")] + public IActionResult Ajax_GetTableList(Model_RepositoryDatabase model) { String messageTitle = Localiser["label.database"]; - AjaxResponse_CoreDatabaseTableList responseData = new AjaxResponse_CoreDatabaseTableList(model); + AjaxResponse_RepositoryTableList responseData = new AjaxResponse_RepositoryTableList(model); // Validate session and referrer. if (!ValidReferer) return Forbid(); diff --git a/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController.cs b/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController.cs similarity index 51% rename from SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController.cs rename to SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController.cs index 33de668..36b1b9f 100644 --- a/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/CoreDatabaseController.cs +++ b/SaBusinessMgrCoreWebControl/Control/Controllers/Instance/RepositoryDatabaseController.cs @@ -3,25 +3,26 @@ using Microsoft.Extensions.Logging; using Sarand.BusinessMgr.Net.Core.Web.App; using Sarand.BusinessMgr.Web.Control.Components; using Sarand.BusinessMgr.Web.Control.Models.Instance; +using Sarand.BusinessMgr.Web.Control.Models.System; namespace Sarand.BusinessMgr.Web.Control.Controllers.Instance { //====================================================================== - public partial class CoreDatabaseController : SbmController_Control + public partial class RepositoryDatabaseController : SbmController_Control { //------------------------------------------------------------------- // Data members. //------------------------------------------------------------------- // Construction. - public CoreDatabaseController(SbmLocaliser localiser, ILogger logger) : + public RepositoryDatabaseController(SbmLocaliser localiser, ILogger logger) : base(localiser, logger) { } //------------------------------------------------------------------- - [Route("Instance/CoreDatabase")] - public IActionResult Index(Model_CoreDatabase model) + [Route("Instance/Repository/Database/Tables")] + public IActionResult DatabaseTables(Model_RepositoryDatabase model) { if (!ValidUserSession) AutoLoginUser(); @@ -38,7 +39,30 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.Instance model.Filter.Context = SessionData_Control.Profile.Filter.InstanceContext; // Core Database view. - return View("Views/Instance/CoreDatabase/Index.cshtml", model); + return View("Views/Instance/Repository/Database/Tables.cshtml", model); + } + + //------------------------------------------------------------------- + [Route("Instance/Repository/Database/Schema")] + public IActionResult Schema() + { + if (!ValidUserSession) + AutoLoginUser(); + + // Redirect to sign-in if not signed-in. + if (!ValidUserSession) + { + ClearKeepLoggedInCookie(); + return RedirectToAction("", "Security"); + } + + // Refresh model. + Model_System model = new Model_System(Localiser); + RefreshModel(model); + model.DatabaseFilter.Instance = SessionData_Control.Profile.Filter.InstanceContext; + + // Core Database view. + return View("Views/Instance/Repository/Database/Schema.cshtml", model); } //------------------------------------------------------------------- diff --git a/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Database.cs b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Database.cs index 6dc4bf2..7466885 100644 --- a/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Database.cs +++ b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Database.cs @@ -72,7 +72,7 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System Sbm.Database databaseInstance = EnumUtil.ParseEnum(StringUtil.EmptyOnNull(model.DatabaseFilter.Instance), Sbm.Database.Unknown); if (databaseInstance <= 0) return Json(responseData.SetMessage(messageTitle, $"Database instance must be specified.")); - ISacsDatabase db = GetDatabase(databaseInstance); + ISacsDatabase db = GetDatabase(databaseInstance, model.DatabaseFilter.Context); if (db == null) return Json(responseData.SetMessage(messageTitle, $"Database unavailable for instance '{databaseInstance}'.")); @@ -123,12 +123,14 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System /// /// Get database by type. /// - private ISacsDatabase GetDatabase(Sbm.Database databaseInstance) + private ISacsDatabase GetDatabase(Sbm.Database databaseInstance, String context) { switch (databaseInstance) { case Sbm.Database.Control: return App.GetControlDatabase(); + case Sbm.Database.BusMgr: + return GetDatabaseByContext(context); case Sbm.Database.Template: return GetDatabaseByContext(Sbm.RepositoryContext_Template); case Sbm.Database.Demo: @@ -169,6 +171,7 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System public AjaxResponse_ValidateDatabaseSchema(SbmModel_Control model) : base(model) { } // Database instance. public String Instance { get; set; } + public String Context { get; set; } // Schema validation list. public List Items { get; } = new List(); } @@ -194,13 +197,21 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System return Json(responseData.SetMessage(messageTitle, "Database instance must be specified")); responseData.Instance = databaseInstance.ToString(); + // Context. + if (databaseInstance == Sbm.Database.BusMgr) + { + if (StringUtil.IsBlank(model.DatabaseFilter.Context)) + return Json(responseData.SetMessage(messageTitle, "BusMgr Database context must be specified")); + responseData.Context = model.DatabaseFilter.Context; + } + // Database connection. - ISacsDatabase db = GetDatabase(databaseInstance); + ISacsDatabase db = GetDatabase(databaseInstance, model.DatabaseFilter.Context); if (db == null) return Json(responseData.SetMessage(messageTitle, $"Unrecognised database instance specified: '{model.DatabaseFilter.Instance}'.")); // Retrieve XML database schema definition. - Dictionary xmlSchemas = GetSmlSchema(databaseInstance); + Dictionary xmlSchemas = GetSmlSchemas(databaseInstance); if (!xmlSchemas.Any()) return Json(responseData.SetMessage(messageTitle, "Failed to extract XML schema definitions.")); @@ -253,7 +264,7 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System return Json(responseData); } - private Dictionary GetSmlSchema(Sbm.Database databaseInstance) + private Dictionary GetSmlSchemas(Sbm.Database databaseInstance) { Dictionary schemas = new Dictionary(); switch (databaseInstance) @@ -264,6 +275,7 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System schemas.Add("SbmDbDfn_Control.xml", SacsResourceHelper.GetManifestResourceAsText(assembly, "", "SbmDbDfn_Control.xml")); break; } + case Sbm.Database.BusMgr: case Sbm.Database.Template: case Sbm.Database.Demo: { @@ -436,8 +448,15 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System if (databaseInstance <= 0) return Json(responseData.SetMessage(messageTitle, "Database instance must be specified")); + // Context. + if (databaseInstance == Sbm.Database.BusMgr) + { + if (StringUtil.IsBlank(model.DatabaseFilter.Context)) + return Json(responseData.SetMessage(messageTitle, "BusMgr Database context must be specified")); + } + // Database connection. - ISacsDatabase db = GetDatabase(databaseInstance); + ISacsDatabase db = GetDatabase(databaseInstance, model.DatabaseFilter.Context); // Table definition. DbDfnTable tableDfn = db.GetTableDfn(model.DatabaseTable.Name, true); diff --git a/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Logs.cs b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Logs.cs new file mode 100644 index 0000000..cc077d2 --- /dev/null +++ b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController-Ajax-Logs.cs @@ -0,0 +1,312 @@ +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using NPOI.SS.Formula.Functions; +using Sarand.BusinessMgr.Net.Core.Web.App; +using Sarand.BusinessMgr.Net.Standard.Dbas.App; +using Sarand.BusinessMgr.Web.Control.Components; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Dbas; +using Sarand.Net.Standard.Base.Helpers; +using Sarand.Net.Standard.Base.Utils; +using Sarand.Net.Standard.Dbas.Data; +using Sarand.Net.Standard.Dbas.Proc; +using System.Collections.Generic; +using System; +using Sarand.BusinessMgr.Web.Control.Models.System; +using Sarand.BusinessMgr.Net.Standard.Base.App; +using DocumentFormat.OpenXml.EMMA; +using System.Linq; +using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control; +using Sarand.Net.Standard.Dbas.Base; +using Sarand.BusinessMgr.Web.Control.Consoles; +using System.Reflection; +using static Sarand.BusinessMgr.Net.Standard.Dbas.Utils.SbmDbDfnGenerator; +using Sarand.Net.Standard.Base.App; +using Sarand.BusinessMgr.Net.Standard.Dbas.Consoles; +using Sarand.Net.Standard.Base.IO; +using System.IO; +using System.Text.RegularExpressions; + +namespace Sarand.BusinessMgr.Web.Control.Controllers.System +{ + //====================================================================== + // System Controller - Ajax - Logs. + //====================================================================== + partial class SystemController + { + //------------------------------------------------------------------- + // Database data. + private class LogFolderData + { + public String Name { get; set; } + } + private class LogFileData + { + public String Name { get; set; } + public String UpdateFmt { get; set; } + public long Size { get; set; } + } + + //------------------------------------------------------------------- + // Get Log Folder List ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_LogFolderList : AjaxResponse_Data + { + // Construction. + public AjaxResponse_LogFolderList(SbmModel_Control model) : base(model) { } + // Log file list. + public List Folders { get; } = new List(); + } + //------------------------------------------------------------------- + /// + /// Retrieve the list of folders under the root folder. + /// - These should correspond to applications (control, busmgr, api etc). + /// + [HttpPost] + [Route("System/Ajax/Logs/GetFolderList")] + [Route("System/Ajax/Logs/GetFolders")] + public IActionResult Ajax_GetLogFolderList(Model_System model) + { + String fn = GetType().Name + ".Ajax_GetLogFolderList"; + String messageTitle = Localiser["system.caption.logs"]; + AjaxResponse_LogFolderList responseData = new AjaxResponse_LogFolderList(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Identify folders in root log folder. + String rootLogFolder = model.LoggingRootFolder; + foreach (String folder in Directory.EnumerateDirectories(rootLogFolder)) + { + String folderName = Path.GetFileName(folder); + if (folderName.IsMatch("^(?:Sbm|BusMgr|Web|)(?:Control|Portal|Api)$", RegexOptions.IgnoreCase)) + responseData.Folders.Add(new LogFolderData() { Name = folderName }); + } + + // Complete response. + responseData.Success = true; + + return Json(responseData); + } + + //------------------------------------------------------------------- + // Get Log Year Folder List ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_LogYearList : AjaxResponse_Data + { + // Construction. + public AjaxResponse_LogYearList(SbmModel_Control model) : base(model) { } + // Log file list. + public List Years { get; } = new List(); + } + //------------------------------------------------------------------- + /// + /// Retrieve the list of year folders under the selected folder. + /// + [HttpPost] + [Route("System/Ajax/Logs/GetYearList")] + [Route("System/Ajax/Logs/GetYears")] + public IActionResult Ajax_GetLogYearList(Model_System model) + { + String fn = GetType().Name + ".Ajax_GetLogYearList"; + String messageTitle = Localiser["system.caption.logs"]; + AjaxResponse_LogYearList responseData = new AjaxResponse_LogYearList(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Store filter properties to session. + SessionData_Control.System.Logs.Filter.Folder = model.LogsFilter.Folder; + SessionData_Control.System.Logs.Filter.Year = ""; + SessionData_Control.System.Logs.Filter.Month = ""; + + // Identify folders in selected log folder. + String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder); + foreach (String folder in Directory.EnumerateDirectories(logFolder)) + { + String folderName = Path.GetFileName(folder); + if (folderName.IsMatch("^\\d{4}$")) + responseData.Years.Add(new LogFolderData() { Name = folderName }); + } + + // Complete response. + responseData.Success = true; + + return Json(responseData); + } + + //------------------------------------------------------------------- + // Get Log Month Folder List ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_LogMonthList : AjaxResponse_Data + { + // Construction. + public AjaxResponse_LogMonthList(SbmModel_Control model) : base(model) { } + // Log file list. + public List Months { get; } = new List(); + } + //------------------------------------------------------------------- + /// + /// Retrieve the list of year folders under the selected folder. + /// + [HttpPost] + [Route("System/Ajax/Logs/GetMonthList")] + [Route("System/Ajax/Logs/GetMonths")] + public IActionResult Ajax_GetLogMonthList(Model_System model) + { + String fn = GetType().Name + ".Ajax_GetLogMonthList"; + String messageTitle = Localiser["system.caption.logs"]; + AjaxResponse_LogMonthList responseData = new AjaxResponse_LogMonthList(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Store filter properties to session. + SessionData_Control.System.Logs.Filter.Folder = model.LogsFilter.Folder; + SessionData_Control.System.Logs.Filter.Year = model.LogsFilter.Year; + SessionData_Control.System.Logs.Filter.Month = ""; + //SessionData_Control.System.Logs.Filter.Month = model.LogsFilter.Month; + + // Identify folders in selected year folder. + String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year); + foreach (String folder in Directory.EnumerateDirectories(logFolder)) + { + String folderName = Path.GetFileName(folder); + if (folderName.IsMatch("^\\d{6}$")) + responseData.Months.Add(new LogFolderData() { Name = folderName }); + } + + // Complete response. + responseData.Success = true; + + return Json(responseData); + } + + //------------------------------------------------------------------- + // Get Log File List ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_LogFileList : AjaxResponse_Data + { + // Construction. + public AjaxResponse_LogFileList(SbmModel_Control model) : base(model) { } + // Log file list. + public List Files { get; } = new List(); + } + //------------------------------------------------------------------- + [HttpPost] + [Route("System/Ajax/Logs/GetFileList")] + [Route("System/Ajax/Logs/GetFiles")] + public IActionResult Ajax_GetLogFileList(Model_System model) + { + String fn = GetType().Name + ".Ajax_GetLogFileList"; + String messageTitle = Localiser["system.caption.logs"]; + AjaxResponse_LogFileList responseData = new AjaxResponse_LogFileList(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Store filter properties to session. + SessionData_Control.System.Logs.Filter.Folder = model.LogsFilter.Folder; + SessionData_Control.System.Logs.Filter.Year = model.LogsFilter.Year; + SessionData_Control.System.Logs.Filter.Month = model.LogsFilter.Month; + + // Identify folders in selected year folder. + String logFolder = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year, model.LogsFilter.Month); + DirectoryInfo folder = new DirectoryInfo(logFolder); + foreach (FileInfo file in folder.EnumerateFiles()) + { + responseData.Files.Add(new LogFileData() { Name = file.Name, UpdateFmt = file.LastWriteTime.ToString("d-MMM-yy HH:mm"), Size = file.Length }); + } + + // Complete response. + responseData.Success = true; + + return Json(responseData); + } + + //------------------------------------------------------------------- + // Get Log File ajax request. + //------------------------------------------------------------------- + private class AjaxResponse_LogFile : AjaxResponse_Data + { + // Construction. + public AjaxResponse_LogFile(SbmModel_Control model) : base(model) { } + // Log file. + public class LogFileData + { + public String Path { get; set; } + public String Name { get; set; } + public String Data { get; set; } + public String Html { get; set; } = ""; + } + public LogFileData File { get; } = new LogFileData(); + } + //------------------------------------------------------------------- + [HttpPost] + [Route("System/Ajax/Logs/GetFile")] + [Route("System/Ajax/Logs/GetLogFile")] + public IActionResult Ajax_GetLogFile(Model_System model) + { + String fn = GetType().Name + ".Ajax_GetLogFile"; + String messageTitle = Localiser["system.caption.logs"]; + AjaxResponse_LogFile responseData = new AjaxResponse_LogFile(model); + + // Validate session. + if (!ValidUserSession) + return GetAjaxResult_InvalidSession(responseData); + + // Store filter properties to session. + SessionData_Control.System.Logs.Filter.Folder = model.LogsFilter.Folder; + SessionData_Control.System.Logs.Filter.Year = model.LogsFilter.Year; + SessionData_Control.System.Logs.Filter.Month = model.LogsFilter.Month; + + // Identify folders in selected year folder. + responseData.File.Path = Path.Combine(model.LoggingRootFolder, model.LogsFilter.Folder, model.LogsFilter.Year, model.LogsFilter.Month, model.LogsFilter.Filename); + responseData.File.Name = Path.GetFileName(responseData.File.Path); + try + { + String[] fileLines = FileUtil.ReadAllFileLines(responseData.File.Path); + responseData.File.Data = String.Join("\n", fileLines); + // Construct html data. + foreach (var fileLine in fileLines) + { + String line = fileLine; + List classNames = new List(); + if (fileLine.IsMatch("^\t{2}")) + { + line = Regex.Replace(fileLine, "^\t+", ""); + classNames.Add("tab2"); + } + if (fileLine.IsMatch("^\t")) + { + line = Regex.Replace(fileLine, "^\t", ""); + classNames.Add("tab"); + } + if (line.IsMatch("\\d{8}:\\d{6}\\s+(error|err)\\s+", RegexOptions.IgnoreCase)) + classNames.Add("err"); + else if (line.IsMatch("\\d{8}:\\d{6}\\s+(warn|wrn)\\s+", RegexOptions.IgnoreCase)) + classNames.Add("wrn"); + else if (line.IsMatch("\\d{8}:\\d{6}\\s+(info|inf)\\s+", RegexOptions.IgnoreCase)) + classNames.Add("inf"); + responseData.File.Html += $"
" + line + "
"; + } + } + catch (Exception exc) + { + SaLogger.Warn($"{SysUtil.Fn} {ExceptionUtil.GetLogMessage(exc, "reading log file", 0)}"); + } + + // Complete response. + responseData.Success = true; + + return Json(responseData); + } + + //------------------------------------------------------------------- + } + //====================================================================== +} diff --git a/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController.cs b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController.cs index f777c8a..e901a76 100644 --- a/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController.cs +++ b/SaBusinessMgrCoreWebControl/Control/Controllers/System/SystemController.cs @@ -1,7 +1,11 @@ -using Microsoft.AspNetCore.Mvc; +using DocumentFormat.OpenXml.EMMA; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Sarand.BusinessMgr.Net.Core.Web.App; using Sarand.BusinessMgr.Web.Control.Components; +using Sarand.BusinessMgr.Web.Control.Models.System; +using Sarand.Net.Standard.Base.Utils; +using System; namespace Sarand.BusinessMgr.Web.Control.Controllers.System { @@ -29,6 +33,34 @@ namespace Sarand.BusinessMgr.Web.Control.Controllers.System return RedirectToAction("", ""); } + //------------------------------------------------------------------- + /// + /// System - Logs. + /// + [HttpGet] + public IActionResult Logs() + { + if (!ValidUserSession) + AutoLoginUser(); + + // Redirect to sign-in if not signed-in. + if (!ValidUserSession) + { + ClearKeepLoggedInCookie(); + return RedirectToAction("", "Security"); + } + + // Refresh model. + Model_System model = new Model_System(Localiser); + RefreshModel(model); + model.LogsFilter.Folder = StringUtil.OnBlank(SessionData_Control.System.Logs.Filter.Folder, "Control"); + model.LogsFilter.Year = StringUtil.OnBlank(SessionData_Control.System.Logs.Filter.Year, DateTime.Today.ToString("yyyy")); + model.LogsFilter.Month = StringUtil.OnBlank(SessionData_Control.System.Logs.Filter.Month, DateTime.Today.ToString("yyyyMM")); + + // Core Database view. + return View("Views/System/Logs.cshtml", model); + } + //------------------------------------------------------------------- } //====================================================================== diff --git a/SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_CoreDatabase.cs b/SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_RepositoryDatabase.cs similarity index 86% rename from SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_CoreDatabase.cs rename to SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_RepositoryDatabase.cs index a3a0290..f88ebfa 100644 --- a/SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_CoreDatabase.cs +++ b/SaBusinessMgrCoreWebControl/Control/Models/Instance/Model_RepositoryDatabase.cs @@ -5,11 +5,11 @@ using System; namespace Sarand.BusinessMgr.Web.Control.Models.Instance { //======================================================================= - public class Model_CoreDatabase : SbmModel_Control + public class Model_RepositoryDatabase : SbmModel_Control { //------------------------------------------------------------------- // Construction. - public Model_CoreDatabase(SbmLocaliser localiser) : + public Model_RepositoryDatabase(SbmLocaliser localiser) : base(localiser) { } diff --git a/SaBusinessMgrCoreWebControl/Control/Models/System/Model_System.cs b/SaBusinessMgrCoreWebControl/Control/Models/System/Model_System.cs index 2a5c7c3..f3437ab 100644 --- a/SaBusinessMgrCoreWebControl/Control/Models/System/Model_System.cs +++ b/SaBusinessMgrCoreWebControl/Control/Models/System/Model_System.cs @@ -24,9 +24,11 @@ namespace Sarand.BusinessMgr.Web.Control.Models.System //------------------------------------------------------------------- // Database page properties. + // ToDo: System-Database model may not be required.. public class DatabaseFilterData { public String Instance { get; set; } + public String Context { get; set; } public String Search { get; set; } } public DatabaseFilterData DatabaseFilter { get; } = new DatabaseFilterData(); @@ -42,8 +44,7 @@ namespace Sarand.BusinessMgr.Web.Control.Models.System List items = new List(); if (ValidUserSession) { - items.Add("Core", Localiser["label.core"]); - items.Add("Reference", Localiser["label.reference"]); + items.Add("Control", Localiser["label.control"]); items.Add("Support", Localiser["label.support"]); } return new SelectList(items, "Code", "Desc"); @@ -51,7 +52,7 @@ namespace Sarand.BusinessMgr.Web.Control.Models.System //------------------------------------------------------------------- // Logs page properties. - public String LoggingRootFolder { get; } = Regex.Replace(SaLogger.LogFolder, "[\\\\/]Admin$", ""); + public String LoggingRootFolder { get; } = Regex.Replace(SaLogger.LogFolder, "[\\\\/](?:Sbm|BusMgr|Web)Control$", ""); // Log file filter. public class LogsFilterData { diff --git a/SaBusinessMgrCoreWebControl/Localisation/SbmControlProperties.resx b/SaBusinessMgrCoreWebControl/Localisation/SbmControlProperties.resx index b51001b..2eb8586 100644 --- a/SaBusinessMgrCoreWebControl/Localisation/SbmControlProperties.resx +++ b/SaBusinessMgrCoreWebControl/Localisation/SbmControlProperties.resx @@ -432,8 +432,8 @@ Initialise Instance - - Core database + + Repository database Core Database @@ -507,4 +507,34 @@ Strength + + Control + + + System Logs + + + Root folder + + + Folder + + + Year + + + Month + + + File + + + Updated + + + Size + + + Repository schema + \ No newline at end of file diff --git a/SaBusinessMgrCoreWebControl/Views/Home/Index.cshtml b/SaBusinessMgrCoreWebControl/Views/Home/Index.cshtml index 53fd381..743a8d9 100644 --- a/SaBusinessMgrCoreWebControl/Views/Home/Index.cshtml +++ b/SaBusinessMgrCoreWebControl/Views/Home/Index.cshtml @@ -126,11 +126,11 @@ - - - - - + + + + + diff --git a/SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Schema.cshtml b/SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Schema.cshtml new file mode 100644 index 0000000..92a5831 --- /dev/null +++ b/SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Schema.cshtml @@ -0,0 +1,112 @@ +@* Instance - Repository Database Schema *@ +@model Model_System +@inject SbmLocaliser Localiser +@{ + ViewData["Title"] = "Instance - Repository Database Schema"; + Model.AdditionalFiles_JS.Add("js/sbc-ins-rep-sch.js"); +} + +
+ + + +
+ + @* Filter form - wrap header to include paging controls. *@ + @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmSchemaFilter", @class = "sbc-form", @onSubmit = "return false;" })) + { + +
+
+
+ @* *@ +
+
@Localiser["caption.database.core"]
+
+ @* Burger menu *@ + +
+
+
+ + @* Filter Panel *@ +
+ @Html.HiddenFor(model => model.DatabaseFilter.Instance, new { @id = "", @class = "FilterInstance" }) +
+
+
@Localiser["label.context"]
+
+ @Html.DropDownListFor(model => model.DatabaseFilter.Context, Model.GetInstanceContextsForSelect(), "", new { @id = "", @class = "FilterContext" }) +
+
+
+
@Localiser["label.search"]
+
+ @Html.TextBoxFor(model => model.DatabaseFilter.Search, new { @id = "", @class = "FilterSearch", @maxlength = "32" }) +
+
+
+
+ + } + +
+
@Localiser["label.schema"]@Localiser["label.table"]@Localiser["label.column"]@Localiser["label.index"]@Localiser["label.comment"]@Localiser["label.schema"]@Localiser["label.table"]@Localiser["label.column"]@Localiser["label.index"]@Localiser["label.comment"]
+ + + + + + + + + + + + +
@Localiser["label.schema"]@Localiser["label.table"]@Localiser["label.column"]@Localiser["label.index"]@Localiser["label.comment"]
+ + + @* Element templates *@ +
+ @* Filter Burger option template - ul is ignored *@ +
    +
  • XXX
  • +
+ @* Schema row template - table is ignored. *@ + + + + + + + + + +
+
+ @* Burger menu *@ + +
+
+ @* Item Burger option template - ul is ignored *@ +
    +
  • XXX
  • +
+
+ + + + diff --git a/SaBusinessMgrCoreWebControl/Views/Instance/CoreDatabase/Index.cshtml b/SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Tables.cshtml similarity index 95% rename from SaBusinessMgrCoreWebControl/Views/Instance/CoreDatabase/Index.cshtml rename to SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Tables.cshtml index f1599e6..5058a0b 100644 --- a/SaBusinessMgrCoreWebControl/Views/Instance/CoreDatabase/Index.cshtml +++ b/SaBusinessMgrCoreWebControl/Views/Instance/Repository/Database/Tables.cshtml @@ -1,9 +1,9 @@ -@* Instance - Core Database*@ -@model Model_CoreDatabase +@* Instance - Repository Database Tables *@ +@model Model_RepositoryDatabase @inject SbmLocaliser Localiser @{ - ViewData["Title"] = "Instance - Core Database"; - Model.AdditionalFiles_JS.Add("js/sbc-ins-coredb.js"); + ViewData["Title"] = "Instance - Repository Database Tables"; + Model.AdditionalFiles_JS.Add("js/sbc-ins-rep-db.js"); }
diff --git a/SaBusinessMgrCoreWebControl/Views/Shared/_Layout.cshtml b/SaBusinessMgrCoreWebControl/Views/Shared/_Layout.cshtml index 12a3738..3654e9a 100644 --- a/SaBusinessMgrCoreWebControl/Views/Shared/_Layout.cshtml +++ b/SaBusinessMgrCoreWebControl/Views/Shared/_Layout.cshtml @@ -128,7 +128,8 @@ @@ -148,7 +149,7 @@ @Localiser["label.system"] diff --git a/SaBusinessMgrCoreWebControl/Views/System/Logs.cshtml b/SaBusinessMgrCoreWebControl/Views/System/Logs.cshtml new file mode 100644 index 0000000..425dbe2 --- /dev/null +++ b/SaBusinessMgrCoreWebControl/Views/System/Logs.cshtml @@ -0,0 +1,120 @@ +@model Model_System +@inject SbmLocaliser Localiser +@{ + ViewData["Title"] = "System - Logs"; + Model.AdditionalFiles_JS.Add("js/sbc-sys-logs.js"); +} + + + +
+ +
+
+
+
@Localiser["system.caption.logs"]
+
+
@(Localiser[
+
+
+
+ @using (@Html.BeginForm(FormMethod.Post, new { @id = "frmLogsFilter", @class = "sbc-form", @onSubmit = "return false;" })) + { + +
+
+
@Localiser["label.root.folder"]
+
@(Model.LoggingRootFolder)
+
+
+
@Localiser["label.folder"]
+
+
+
+
@Localiser["label.year"]
+
+
+
+
@Localiser["label.month"]
+
+
+
+ } +
+ +
+
+ @* Log file list. *@ +
+ + + + + + + + + +
@Localiser["label.file"]@Localiser["label.updated"]@Localiser["label.size"]
+
+ @* Log file template. *@ + + + + + + +
+
+ +
+ +
+
+ +
+
+
+ +
+ + \ No newline at end of file diff --git a/SaBusinessMgrCoreWebControl/Views/_ViewImports.cshtml b/SaBusinessMgrCoreWebControl/Views/_ViewImports.cshtml index fe268c1..745164b 100644 --- a/SaBusinessMgrCoreWebControl/Views/_ViewImports.cshtml +++ b/SaBusinessMgrCoreWebControl/Views/_ViewImports.cshtml @@ -6,4 +6,5 @@ @using Sarand.BusinessMgr.Web.Control.Models.Account @using Sarand.BusinessMgr.Web.Control.Models.Instance @using Sarand.BusinessMgr.Web.Control.Models.Param +@using Sarand.BusinessMgr.Web.Control.Models.System @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-home.js b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-home.js index 29bd5e0..3cb94fd 100644 --- a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-home.js +++ b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-home.js @@ -27,7 +27,7 @@ var $msgs = $('.sbc-panel-messages', $pnlSchema).hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); } $('.DatabaseInstance', $frm.dbSchema).val(instance); - sbc.ajax.dbSchema = sbc.ajax.dbSchema || { url: sbc.url.base + 'System/Ajax/ValidateDatabaseSchema', formId: $frm.dbSchema.prop('id'), callbackFn: ch.handleDbSchemaResponse, noWaitIcon: true }; + sbc.ajax.dbSchema = sbc.ajax.dbSchema || { url: sbc.url.base + 'System/Ajax/ValidateDatabaseSchema', formSel: $frm.dbSchema, callbackFn: ch.handleDbSchemaResponse, noWaitIcon: true }; sbc.doAjaxRequest(sbc.ajax.dbSchema, delay || 50); ch.awaitingSchemaResponse = true; } diff --git a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-coredb.js b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-db.js similarity index 96% rename from SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-coredb.js rename to SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-db.js index 592c05e..1638b3f 100644 --- a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-coredb.js +++ b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-db.js @@ -18,7 +18,7 @@ env.$pnl.table.find('tbody tr').remove(); env.$pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); } - env.ajax.tables = env.ajax.tables || { url: sbc.url.base + 'Instance/CoreDatabase/Ajax/GetTables', formSel: env.$frm.filter, callbackFn: function (response) { cd.displayItems(env, response); } }; + env.ajax.tables = env.ajax.tables || { url: sbc.url.base + 'Instance/Repository/Ajax/GetTables', formSel: env.$frm.filter, callbackFn: function (response) { cd.displayItems(env, response); } }; sbc.doAjaxRequest(env.ajax.tables, delay || 50); cd.awaitingRefreshResponse = true; } diff --git a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-sch.js b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-sch.js new file mode 100644 index 0000000..617f368 --- /dev/null +++ b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-ins-rep-sch.js @@ -0,0 +1,81 @@ +/* + * SBM - Control - Instance - Core Database. + */ + +(function (win, doc, undef) +{ + "use strict"; + let ds = sbc.mdl.repDbSchema = { env: {}, data: {} }; + let $pnl = ds.$pnl = {}, $frm = ds.$frm = {}, $dlg = ds.$dlg = {}; + + //-------------------------------------------------------------- + ds.refreshDbSchema = function (delay) + { + if (sbc.awaitingLogin) return; + if (!$frm.filter.find('.FilterContext').val()) return; + if (!ds.awaitingSchemaResponse) + { + $pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); + } + ds.clearItems(); + sbc.ajax.dbSchema = sbc.ajax.dbSchema || { url: sbc.url.base + 'System/Ajax/ValidateDatabaseSchema', formSel: $frm.filter, callbackFn: ds.handleDbSchemaResponse, noWaitIcon: true }; + sbc.doAjaxRequest(sbc.ajax.dbSchema, delay || 50); + ds.awaitingSchemaResponse = true; + } + ds.handleDbSchemaResponse = function (response) + { + //sbc.debug('handleDbSchemaResponse', response); + delete ds.awaitingSchemaResponse; + $pnl.msgs.hide().empty(); + var $table = $pnl.table.find('table.sbc-item-list'); + ds.clearItems(); + if (!response.success) return; + // Items. + var items = response.items; + if (!items.length) + return $pnl.msgs.append($('
' + sbc.msg.dbSchemaValid + '
')).fadeIn(500); + for (const item of items) + $table.append(ds.populateDbSchemaItem(ds.getDbSchemaRowTemplate(), item)); + } + ds.getDbSchemaTableTemplate = function () + { + return $pnl.tmpl.find('.sbc-panel-item-table.Schema').clone().hide(); + } + ds.getDbSchemaRowTemplate = function () + { + return $pnl.tmpl.find('.sbc-row-item.SchemaItem').clone(); + } + ds.populateDbSchemaItem = function ($item, item) + { + if (!item) return; + $item.prop('id', sbc.itemIdPrefix + item.id); + $('.SchemaName', $item).text(item.schemaName); + $('.TableName', $item).text(item.tableName); + $('.IndexName', $item).text(item.indexName); + $('.ColumnName', $item).text(item.columnName); + $('.Comment', $item).text(item.comment); + return $item; + } + ds.clearItems = function () + { + $pnl.table.find('table.sbc-item-list').find('tbody tr').remove(); + } + + //-------------------------------------------------------------- + $(function () + { + $pnl.items = $('.sbc-panel.Schema'); + $frm.filter = $pnl.items.find('#frmSchemaFilter'); + $frm.filter.on('change', '.FilterContext', ds.refreshDbSchema); + $frm.filter.on('input', '.FilterSearch', ds.refreshDbSchema); + $frm.filter.find('.FilterInstance').val('BusMgr'); + $pnl.table = $pnl.items.find('.sbc-panel-item-table'); + $pnl.msgs = $pnl.items.find('.sbc-panel-messages'); + $pnl.tmpl = $pnl.items.find('.sbc-panel-item-template'); + setTimeout(function () { ds.refreshDbSchema(); }, 500); + }); + + //-------------------------------------------------------------- +}(window, window.document)); + +/* The End */ \ No newline at end of file diff --git a/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-sys-logs.js b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-sys-logs.js new file mode 100644 index 0000000..2e25bae --- /dev/null +++ b/SaBusinessMgrCoreWebControl/wwwroot/js/sbc-sys-logs.js @@ -0,0 +1,289 @@ +/* + * Admin - System Logs page scripts. + */ + +(function (win, doc, undef) +{ + "use strict"; + let sl = sbc.sysLogs = { data: {}, $pnl: {}, $frm: {}, $ctrl: {}, $dlg: {} }; + let $pnl = sl.$pnl; let $frm = sl.$frm; let $ctrl = sl.$ctrl; let $dlg = sl.$dlg; + + //-------------------------------------------------------------- + sl.refreshFolders = function (delay) + { + if (!sl.data.awaitingRefreshFoldersResponse) + { + sl.clearFiles(); + //$pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); + } + sbc.ajax.refreshFolders = sbc.ajax.refreshFolders || { url: sbc.url.base + 'System/Ajax/Logs/GetFolders', formSel: sl.$frm.filter, callbackFn: sl.doRefreshFolders }; + sbc.doAjaxRequest(sbc.ajax.refreshFolders, delay || 50); + sl.data.awaitingRefreshFoldersResponse = true; + } + sl.doRefreshFolders = function (response) + { + sbc.debug('doRefreshFolders', response); + delete sl.data.awaitingRefreshFoldersResponse; + sl.clearFilterFolders(); + sbc.refreshControlValues(response.controlValues); + $pnl.msgs.hide().empty(); + if (!response.success) return; + // Folders. + var items = response.folders; + if (!items.length) + return $pnl.msgs.append($('
' + sbc.msg.dataNoneFound + '
')).fadeIn(500); + for (const item of items) + $ctrl.cbFolders.append($('')); + if (sbc.data.logFolder) $ctrl.cbFolders.val(sbc.data.logFolder); + if (!$ctrl.cbFolders.val()) $ctrl.cbFolders.val(items[0].name); + delete sbc.data.logFolder; + if ($ctrl.cbFolders.val()) $ctrl.cbFolders.trigger('change'); + } + + //-------------------------------------------------------------- + sl.clearFilterFolders = function () + { + sl.clearFilterYears(); + $('option', $ctrl.cbFolders).remove(); + } + sl.clearFilterYears = function () + { + sl.clearFilterMonths(); + $('option', $ctrl.cbYears).remove(); + } + sl.clearFilterMonths = function () + { + sl.clearFiles(); + $('option', $ctrl.cbMonths).remove(); + } + sl.clearFiles = function () + { + $pnl.msgs.hide().empty(); + $pnl.list.find('tbody tr').remove(); + } + + //-------------------------------------------------------------- + sl.refreshYears = function (delay) + { + if (!sl.data.awaitingRefreshYearsResponse) + { + sl.clearFiles(); + //$pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); + } + sbc.ajax.refreshYears = sbc.ajax.refreshYears || { url: sbc.url.base + 'System/Ajax/Logs/GetYears', formSel: sl.$frm.filter, callbackFn: sl.doRefreshYears }; + sbc.doAjaxRequest(sbc.ajax.refreshYears, delay || 50); + sl.data.awaitingRefreshYearsResponse = true; + } + sl.doRefreshYears = function (response) + { + //sbc.debug('doRefreshYears', response); + delete sl.data.awaitingRefreshYearsResponse; + sl.clearFilterYears(); + sbc.refreshControlValues(response.controlValues); + $pnl.msgs.hide().empty(); + if (!response.success) return; + // Years. + var items = response.years; + if (!items.length) + return $pnl.msgs.append($('
' + sbc.msg.dataNoneFound + '
')).fadeIn(500); + for (let itemIdx = 0; itemIdx < items.length; itemIdx++) + $ctrl.cbYears.append($('')); + if (sbc.data.logYear) $ctrl.cbYears.val(sbc.data.logYear); + delete sbc.data.logYear; + if ($ctrl.cbYears.val()) $ctrl.cbYears.trigger('change'); + } + + //-------------------------------------------------------------- + sl.refreshMonths = function (delay) + { + if (!sl.data.awaitingRefreshMonthsResponse) + { + sl.clearFiles(); + //$pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); + } + sbc.ajax.refreshMonths = sbc.ajax.refreshMonths || { url: sbc.url.base + 'System/Ajax/Logs/GetMonths', formSel: sl.$frm.filter, callbackFn: sl.doRefreshMonths }; + sbc.doAjaxRequest(sbc.ajax.refreshMonths, delay || 50); + sl.data.awaitingRefreshMonthsResponse = true; + } + sl.doRefreshMonths = function (response) + { + //sbc.debug('doRefreshMonths', response); + delete sl.data.awaitingRefreshMonthsResponse; + sl.clearFilterMonths(); + sbc.refreshControlValues(response.controlValues); + $pnl.msgs.hide().empty(); + if (!response.success) return; + sbc.data.logYear = $ctrl.cbYears.val(); + // Months. + var items = response.months; + if (!items.length) + return $pnl.msgs.append($('
' + sbc.msg.dataNoneFound + '
')).fadeIn(500); + for (let itemIdx = 0; itemIdx < items.length; itemIdx++) + $ctrl.cbMonths.append($('')); + if (sbc.data.logMonth) $ctrl.cbMonths.val(sbc.data.logMonth); + if (!$ctrl.cbMonths.val() && items.length) $ctrl.cbMonths.val(items[0].name); + delete sbc.data.logMonth; + if ($ctrl.cbMonths.val()) $ctrl.cbMonths.trigger('change'); + } + + //-------------------------------------------------------------- + sl.refreshFiles = function (delay) + { + if (!sl.data.awaitingRefreshFilesResponse) + { + sl.clearFiles(); + //$pnl.msgs.hide().empty().append($('
' + sbc.msg.dataQuerying + '
')).fadeIn(200); + } + sbc.ajax.refreshFiles = sbc.ajax.refreshFiles || { url: sbc.url.base + 'System/Ajax/Logs/GetFiles', formSel: sl.$frm.filter, callbackFn: sl.doRefreshFiles }; + sbc.doAjaxRequest(sbc.ajax.refreshFiles, delay || 50); + sl.data.awaitingRefreshFilesResponse = true; + } + sl.doRefreshFiles = function (response) + { + //sbc.debug('doRefreshFiles', response); + delete sl.data.awaitingRefreshFilesResponse; + sl.clearFiles(); + sbc.refreshControlValues(response.controlValues); + if (!response.success) return; + sbc.data.logMonth = $ctrl.cbMonths.val(); + // Files. + var items = response.files; + sl.data.files = response.files; + if (!(items || []).length) + return $pnl.msgs.append($('
' + sbc.msg.dataNoneFound + '
')).fadeIn(500); + for (let itemIdx = 0; itemIdx < items.length; itemIdx++) + $pnl.list.append(sl.populateItem(sl.getFileTemplate(), items[itemIdx])); + $pnl.list.fadeIn(50); + } + sl.populateItem = function ($item, item) + { + if (!item) return $item; + $item.off('click').on('click', function () { sl.showFile(item.name) }); + $('.Filename', $item).text(item.name); + $('.Updated', $item).text(item.updateFmt); + $('.Size', $item).text(sbc.formatFileSize(item.size, 2)); + return $item; + } + sl.getFileTemplate = function () + { + return $('.sbc-panel-item-template .sbc-panel-item.LogFile', $pnl.results).clone(); + } + + //-------------------------------------------------------------- + sl.showFile = function (filename, delay) + { + $('.FilterLogFilename', $frm.filter).val(filename); + sl.setFileTitle(filename); + if (!sl.data.awaitingGetFileResponse) + { + sl.setFileData($('
' + sbc.msg.dataQuerying + '
')); + sl.openFileDlg(); + } + sbc.ajax.getFile = sbc.ajax.getFile || { url: sbc.url.base + 'System/Ajax/Logs/GetFile', formSel: sl.$frm.filter, callbackFn: sl.onShowFile }; + sbc.doAjaxRequest(sbc.ajax.getFile, delay || 50); + sl.data.awaitingGetFileResponse = true; + } + sl.onShowFile = function (response) + { + //sbc.debug('doGetFiles', response); + delete sl.data.awaitingGetFileResponse; + $pnl.msgs.hide().empty(); + if (!response.success) return; + + // Configure file action buttons. + let files = sl.data.files; + let filename = response.file.name; + $ctrl.filePrev.prop('disabled', (files || []).length < 2 || !filename || files[0].name == filename); + $ctrl.fileNext.prop('disabled', (files || []).length < 2 || !filename || files[files.length - 1].name == filename); + + // Display table details. + sl.setFileTitle(filename || response.popupTitle); + $('.LogFilename', $dlg.file).val(filename); + sl.setFileData(response.file.html); + sl.openFileDlg(); + } + sl.openFileDlg = function () + { + sbc.openDialog($dlg.file, $(win).width(), $(win).height()); + } + sl.setFileTitle = function (filename) + { + $dlg.file.dialog('option', 'title', "File: " + filename); + } + sl.setFileData = function (data) + { + $('.FileData', $dlg.file).html(data); + } + + //-------------------------------------------------------------- + sl.onCreateLogFileDlg = function () + { + let $btnPane = $('#dlgLogFile + div.ui-dialog-buttonpane'); + $pnl.logFileActions = $('
'); + $ctrl.filePrev = $('
diff --git a/SaBusinessMgrCoreWebPortal/Views/Shared/_Layout.cshtml b/SaBusinessMgrCoreWebPortal/Views/Shared/_Layout.cshtml index 5eb4a3f..aef76d6 100644 --- a/SaBusinessMgrCoreWebPortal/Views/Shared/_Layout.cshtml +++ b/SaBusinessMgrCoreWebPortal/Views/Shared/_Layout.cshtml @@ -109,9 +109,11 @@