diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/LoginRequestHandlerTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/LoginRequestHandlerTests.cs index bd8c87d9..1857a794 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/LoginRequestHandlerTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/LoginRequestHandlerTests.cs @@ -29,9 +29,9 @@ public async Task LoginRequestHandler_Handle_LoginRequest_IsHandled() authenticationService.Setup(a => a.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); configurationService.Setup(c => c.GetConfiguration(It.IsAny(), It.IsAny())).ReturnsAsync(new Configuration()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, memoryCacheService.Object); + LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, applicationCache.Object); LoginRequest request = LoginRequest.Create(TestData.UserName,TestData.Password); @@ -57,9 +57,9 @@ public async Task LoginRequestHandler_Handle_RefreshTokenRequest_IsHandled() }); authenticationService.Setup(a => a.RefreshAccessToken(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); configurationService.Setup(c => c.GetConfiguration(It.IsAny(), It.IsAny())).ReturnsAsync(new Configuration()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, memoryCacheService.Object); + LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, applicationCache.Object); RefreshTokenRequest request = RefreshTokenRequest.Create(TestData.RefreshToken); @@ -85,9 +85,9 @@ public async Task LoginRequestHandler_Handle_GetConfigurationRequest_IsHandled() }); authenticationService.Setup(a => a.GetToken(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); configurationService.Setup(c => c.GetConfiguration(It.IsAny(), It.IsAny())).ReturnsAsync(new Configuration()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, memoryCacheService.Object); + LoginRequestHandler handler = new LoginRequestHandler(authenticationServiceResolver, configurationServiceResolver, applicationCache.Object); GetConfigurationRequest request = GetConfigurationRequest.Create(TestData.DeviceIdentifier); diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/MerchantRequestHandlerTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/MerchantRequestHandlerTests.cs index d24565c5..b67a82f1 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/MerchantRequestHandlerTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/MerchantRequestHandlerTests.cs @@ -26,10 +26,9 @@ public async Task MerchantRequestHandler_GetContractProductsRequest_Handle_IsHan merchantService.Setup(m => m.GetContractProducts(It.IsAny())) .ReturnsAsync(TestData.ContractProductList); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - - MerchantRequestHandler handler = new MerchantRequestHandler(merchantServiceResolver, memoryCacheService.Object); + MerchantRequestHandler handler = new MerchantRequestHandler(merchantServiceResolver, applicationCache.Object); GetContractProductsRequest request = GetContractProductsRequest.Create(); @@ -48,8 +47,8 @@ public async Task MerchantRequestHandler_GetMerchantBalanceRequest_Handle_IsHand }); merchantService.Setup(m => m.GetMerchantBalance(It.IsAny())) .ReturnsAsync(TestData.MerchantBalance); - Mock memoryCacheService = new Mock(); - MerchantRequestHandler handler = new MerchantRequestHandler(merchantServiceResolver, memoryCacheService.Object); + Mock applicationCache = new Mock(); + MerchantRequestHandler handler = new MerchantRequestHandler(merchantServiceResolver, applicationCache.Object); GetMerchantBalanceRequest request = GetMerchantBalanceRequest.Create(); diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/SupportRequestHandlerTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/SupportRequestHandlerTests.cs index db145f6d..2cfa2e12 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/SupportRequestHandlerTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/SupportRequestHandlerTests.cs @@ -25,9 +25,9 @@ public async Task SupportRequestHandlerTests_UploadLogsRequest_NoLogs_Handle_IsH Mock databaseContext = new Mock(); databaseContext.Setup(d => d.GetLogMessages(It.IsAny())).ReturnsAsync(new List()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, memoryCacheService.Object); + SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object); UploadLogsRequest request = UploadLogsRequest.Create(TestData.DeviceIdentifier); @@ -59,9 +59,9 @@ public async Task SupportRequestHandlerTests_UploadLogsRequest_LogsToUpload_Only new Database.LogMessage() }).ReturnsAsync(new List()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, memoryCacheService.Object); + SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object); UploadLogsRequest request = UploadLogsRequest.Create(TestData.DeviceIdentifier); @@ -101,9 +101,9 @@ public async Task SupportRequestHandlerTests_UploadLogsRequest_LogsToUpload_15Me new Database.LogMessage(), }).ReturnsAsync(new List()); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); - SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, memoryCacheService.Object); + SupportRequestHandler handler = new SupportRequestHandler(configurationServiceResolver, databaseContext.Object, applicationCache.Object); UploadLogsRequest request = UploadLogsRequest.Create(TestData.DeviceIdentifier); diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs index 3d885ef5..22b88d2d 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/RequestHandlerTests/TransactionRequestHandlerTests.cs @@ -24,9 +24,9 @@ public async Task TransactionRequestHandler_LogonTransactionRequest_Handle_IsHan return transactionService.Object; }); Mock databaseContext = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); transactionService.Setup(t => t.PerformLogon(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.PerformLogonResponseModel); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, memoryCacheService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, applicationCache.Object); LogonTransactionRequest request = LogonTransactionRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, @@ -47,9 +47,9 @@ public async Task TransactionRequestHandler_PerformMobileTopupRequest_Handle_IsH return transactionService.Object; }); Mock databaseContext = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); transactionService.Setup(t => t.PerformMobileTopup(It.IsAny(), It.IsAny())).ReturnsAsync(true); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, memoryCacheService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, applicationCache.Object); PerformMobileTopupRequest request = PerformMobileTopupRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, @@ -76,9 +76,9 @@ public async Task TransactionRequestHandler_PerformVoucherIssueRequest_Handle_Is return transactionService.Object; }); Mock databaseContext = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); transactionService.Setup(t => t.PerformVoucherIssue(It.IsAny(), It.IsAny())).ReturnsAsync(true); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, memoryCacheService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, applicationCache.Object); PerformVoucherIssueRequest request = PerformVoucherIssueRequest.Create(TestData.TransactionDateTime, TestData.TransactionNumber, @@ -106,10 +106,10 @@ public async Task TransactionRequestHandler_PerformReconciliationRequest_NoTrans return transactionService.Object; }); Mock databaseContext = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); transactionService.Setup(t => t.PerformReconciliation(It.IsAny(), It.IsAny())).ReturnsAsync(true); databaseContext.Setup(d => d.GetTransactions()).ReturnsAsync(new List()); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, memoryCacheService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, applicationCache.Object); PerformReconciliationRequest request = PerformReconciliationRequest.Create(TestData.TransactionDateTime, TestData.DeviceIdentifier, @@ -129,11 +129,11 @@ public async Task TransactionRequestHandler_PerformReconciliationRequest_Transac return transactionService.Object; }); Mock databaseContext = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); transactionService.Setup(t => t.PerformReconciliation(It.IsAny(), It.IsAny())).ReturnsAsync(true); databaseContext.Setup(d => d.GetTransactions()).ReturnsAsync(TestData.StoredTransactions); - TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, memoryCacheService.Object); + TransactionRequestHandler handler = new TransactionRequestHandler(transactionServiceResolver, databaseContext.Object, applicationCache.Object); PerformReconciliationRequest request = PerformReconciliationRequest.Create(TestData.TransactionDateTime, TestData.DeviceIdentifier, diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/TestData.cs b/TransactionMobile.Maui.BusinessLogic.Tests/TestData.cs index 6b4635e3..96f14578 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/TestData.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/TestData.cs @@ -20,6 +20,11 @@ public static class TestData RefreshToken = TestData.RefreshToken }; + public static Configuration Configuration = new Configuration(); + public static Configuration NullConfiguration = null; + + public static TokenResponseModel NullAccessToken => null; + public static String Token = "Token"; public static String RefreshToken = "RefreshToken"; @@ -115,6 +120,8 @@ public static class TestData TestData.Operator3Product_200KES }; + public static List ContractProductListEmpty = new List(); + public static ContractOperatorModel ContractOperatorModel = new ContractOperatorModel { OperatorIdentfier = TestData.OperatorIdentifier1, @@ -174,6 +181,16 @@ public static class TestData RequireApplicationUpdate = false, ResponseMessage = "SUCCESS" }; + + public static PerformLogonResponseModel PerformLogonResponseModelFailed => + new PerformLogonResponseModel + { + EstateId = TestData.EstateId, + MerchantId = TestData.MerchantId, + IsSuccessful = false, + RequireApplicationUpdate = false, + ResponseMessage = "FAILED" + }; } } \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/AdminPageViewModelTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/AdminPageViewModelTests.cs index a565624f..e77d6d83 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/AdminPageViewModelTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/AdminPageViewModelTests.cs @@ -14,7 +14,6 @@ namespace TransactionMobile.Maui.BusinessLogic.Tests.ViewModelTests using ViewModels.Transactions; using Xunit; using TransactionMobile.Maui.BusinessLogic.Services; - using ViewModels.MyAccount; public class AdminPageViewModelTests { @@ -23,12 +22,10 @@ public void AdminPageViewModel_AdminCommand_Execute_IsExecuted() { Mock navigationService = new Mock(); Mock mediator = new Mock(); - Mock memoryCacheService = new Mock(); Mock deviceService = new Mock(); Mock applicationInfoService = new Mock(); AdminPageViewModel viewModel = new AdminPageViewModel(mediator.Object, navigationService.Object, - memoryCacheService.Object, deviceService.Object, applicationInfoService.Object); @@ -36,19 +33,4 @@ public void AdminPageViewModel_AdminCommand_Execute_IsExecuted() navigationService.Verify(n => n.GoToHome(), Times.Once); } } - - public class MyAccountPageViewModelTests - { - [Fact] - public void MyAccountPageViewModel_LogoutCommand_Execute_IsExecuted() - { - Mock navigationService = new Mock(); - Mock memoryCacheService = new Mock(); - MyAccountPageViewModel viewModel = new MyAccountPageViewModel(navigationService.Object, - memoryCacheService.Object); - - viewModel.LogoutCommand.Execute(null); - navigationService.Verify(n => n.GoToLoginPage(), Times.Once); - } - } } diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/LoginPageViewModelTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/LoginPageViewModelTests.cs index e2fcdbef..419c08da 100644 --- a/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/LoginPageViewModelTests.cs +++ b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/LoginPageViewModelTests.cs @@ -22,16 +22,20 @@ public void LoginPageViewModel_LoginCommand_Execute_IsExecuted() { Mock mediator = new Mock(); Mock navigationService = new Mock(); - Mock memoryCacheService = new Mock(); + Mock applicationCache = new Mock(); Mock deviceService = new Mock(); Mock applicationInfoService = new Mock(); - LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, memoryCacheService.Object, - deviceService.Object,applicationInfoService.Object); + Mock dialogService = new Mock(); + + LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, applicationCache.Object, + deviceService.Object,applicationInfoService.Object, + dialogService.Object); Logger.Initialise(NullLogger.Instance); mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(new Configuration()); mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.PerformLogonResponseModel); - + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductList); + viewModel.LoginCommand.Execute(null); mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); @@ -40,4 +44,138 @@ public void LoginPageViewModel_LoginCommand_Execute_IsExecuted() mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); navigationService.Verify(n => n.GoToHome(), Times.Once); } + + [Fact] + public void LoginPageViewModel_LoginCommand_Execute_ErrorGettingConfig_WarningToastIsShown() + { + Mock mediator = new Mock(); + Mock navigationService = new Mock(); + Mock applicationCache = new Mock(); + Mock deviceService = new Mock(); + Mock applicationInfoService = new Mock(); + Mock dialogService = new Mock(); + + LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, applicationCache.Object, + deviceService.Object, applicationInfoService.Object, + dialogService.Object); + Logger.Initialise(NullLogger.Instance); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.NullConfiguration); + + viewModel.LoginCommand.Execute(null); + + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + navigationService.Verify(n => n.GoToHome(), Times.Never); + + dialogService.Verify(n => n.ShowWarningToast(It.IsAny(), + null, + "OK", + null, + CancellationToken.None), Times.Once); + } + + [Fact] + public void LoginPageViewModel_LoginCommand_Execute_ErrorGettingToken_WarningToastIsShown() + { + Mock mediator = new Mock(); + Mock navigationService = new Mock(); + Mock applicationCache = new Mock(); + Mock deviceService = new Mock(); + Mock applicationInfoService = new Mock(); + Mock dialogService = new Mock(); + + LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, applicationCache.Object, + deviceService.Object, applicationInfoService.Object, + dialogService.Object); + Logger.Initialise(NullLogger.Instance); + + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Configuration); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.NullAccessToken); + + viewModel.LoginCommand.Execute(null); + + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + navigationService.Verify(n => n.GoToHome(), Times.Never); + + dialogService.Verify(n => n.ShowWarningToast(It.IsAny(), + null, + "OK", + null, + CancellationToken.None), Times.Once); + } + + [Fact] + public void LoginPageViewModel_LoginCommand_Execute_ErrorDuringLogonTransaction_WarningToastIsShown() + { + Mock mediator = new Mock(); + Mock navigationService = new Mock(); + Mock applicationCache = new Mock(); + Mock deviceService = new Mock(); + Mock applicationInfoService = new Mock(); + Mock dialogService = new Mock(); + + LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, applicationCache.Object, + deviceService.Object, applicationInfoService.Object, + dialogService.Object); + Logger.Initialise(NullLogger.Instance); + + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Configuration); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.PerformLogonResponseModelFailed); + + viewModel.LoginCommand.Execute(null); + + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + navigationService.Verify(n => n.GoToHome(), Times.Never); + + dialogService.Verify(n => n.ShowWarningToast(It.IsAny(), + null, + "OK", + null, + CancellationToken.None), Times.Once); + } + + [Fact] + public void LoginPageViewModel_LoginCommand_Execute_ErrorDuringGetContractProducts_WarningToastIsShown() + { + Mock mediator = new Mock(); + Mock navigationService = new Mock(); + Mock applicationCache = new Mock(); + Mock deviceService = new Mock(); + Mock applicationInfoService = new Mock(); + Mock dialogService = new Mock(); + + LoginPageViewModel viewModel = new LoginPageViewModel(mediator.Object, navigationService.Object, applicationCache.Object, + deviceService.Object, applicationInfoService.Object, + dialogService.Object); + Logger.Initialise(NullLogger.Instance); + + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.Configuration); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.AccessToken); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.PerformLogonResponseModel); + mediator.Setup(m => m.Send(It.IsAny(), It.IsAny())).ReturnsAsync(TestData.ContractProductListEmpty); + + viewModel.LoginCommand.Execute(null); + + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Once); + mediator.Verify(x => x.Send(It.IsAny(), It.IsAny()), Times.Never); + navigationService.Verify(n => n.GoToHome(), Times.Never); + + dialogService.Verify(n => n.ShowWarningToast(It.IsAny(), + null, + "OK", + null, + CancellationToken.None), Times.Once); + } } \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/MyAccountPageViewModelTests.cs b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/MyAccountPageViewModelTests.cs new file mode 100644 index 00000000..a8071d1e --- /dev/null +++ b/TransactionMobile.Maui.BusinessLogic.Tests/ViewModelTests/MyAccountPageViewModelTests.cs @@ -0,0 +1,22 @@ +namespace TransactionMobile.Maui.BusinessLogic.Tests.ViewModelTests; + +using Maui.UIServices; +using Moq; +using Services; +using ViewModels.MyAccount; +using Xunit; + +public class MyAccountPageViewModelTests +{ + [Fact] + public void MyAccountPageViewModel_LogoutCommand_Execute_IsExecuted() + { + Mock navigationService = new Mock(); + Mock applicationCache = new Mock(); + MyAccountPageViewModel viewModel = new MyAccountPageViewModel(navigationService.Object, + applicationCache.Object); + + viewModel.LogoutCommand.Execute(null); + navigationService.Verify(n => n.GoToLoginPage(), Times.Once); + } +} \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/LoginRequestHandler.cs b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/LoginRequestHandler.cs index 713f949c..84720881 100644 --- a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/LoginRequestHandler.cs +++ b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/LoginRequestHandler.cs @@ -11,17 +11,16 @@ public class LoginRequestHandler : IRequestHandler ConfigurationServiceResolver; - private readonly IMemoryCacheService MemoryCacheService; + private readonly IApplicationCache ApplicationCache; #region Constructors public LoginRequestHandler(Func authenticationServiceResolver, Func configurationServiceResolver, - IMemoryCacheService memoryCacheService) + IApplicationCache applicationCache) { this.ConfigurationServiceResolver = configurationServiceResolver; - + this.ApplicationCache = applicationCache; this.AuthenticationServiceResolver = authenticationServiceResolver; - this.MemoryCacheService = memoryCacheService; } #endregion @@ -35,11 +34,10 @@ public LoginRequestHandler(Func authenticationSe #region Methods public async Task Handle(LoginRequest request, - CancellationToken cancellationToken) - { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + CancellationToken cancellationToken) { + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); - var authenticationService = this.AuthenticationServiceResolver(useTrainingMode); + IAuthenticationService authenticationService = this.AuthenticationServiceResolver(useTrainingMode); TokenResponseModel token = await authenticationService.GetToken(request.UserName, request.Password, cancellationToken); @@ -49,9 +47,9 @@ public async Task Handle(LoginRequest request, public async Task Handle(GetConfigurationRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); - var configurationService = this.ConfigurationServiceResolver(useTrainingMode); + IConfigurationService configurationService = this.ConfigurationServiceResolver(useTrainingMode); return await configurationService.GetConfiguration(request.DeviceIdentifier, cancellationToken); } @@ -61,9 +59,9 @@ public async Task Handle(GetConfigurationRequest request, public async Task Handle(RefreshTokenRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); - - var authenticationService = this.AuthenticationServiceResolver(useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); + + IAuthenticationService authenticationService = this.AuthenticationServiceResolver(useTrainingMode); TokenResponseModel token = await authenticationService.RefreshAccessToken(request.RefreshToken, cancellationToken); diff --git a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs index 1ad8044e..5e995215 100644 --- a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs +++ b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/MerchantRequestHandler.cs @@ -13,15 +13,15 @@ public class MerchantRequestHandler : IRequestHandler MerchantServiceResolver; - private readonly IMemoryCacheService MemoryCacheService; - + private readonly IApplicationCache ApplicationCache; + #endregion #region Constructors - public MerchantRequestHandler(Func merchantServiceResolver,IMemoryCacheService memoryCacheService) + public MerchantRequestHandler(Func merchantServiceResolver,IApplicationCache applicationCache) { this.MerchantServiceResolver = merchantServiceResolver; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; } #endregion @@ -31,16 +31,13 @@ public MerchantRequestHandler(Func merchantServiceRes public async Task> Handle(GetContractProductsRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue>("ContractProducts", out List products); - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); - - var merchantService = this.MerchantServiceResolver(useTrainingMode); + List products = this.ApplicationCache.GetContractProducts(); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); + IMerchantService merchantService = this.MerchantServiceResolver(useTrainingMode); if (products == null || products.Any() == false) { products = await merchantService.GetContractProducts(cancellationToken); - - this.CacheContractData(products); } if (request.ProductType.HasValue) @@ -52,28 +49,11 @@ public async Task> Handle(GetContractProductsRequest } public async Task Handle(GetMerchantBalanceRequest request, - CancellationToken cancellationToken) - { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); - var merchantService = this.MerchantServiceResolver(useTrainingMode); - + CancellationToken cancellationToken) { + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); + IMerchantService merchantService = this.MerchantServiceResolver(useTrainingMode); return await merchantService.GetMerchantBalance(cancellationToken); } - - private void CacheContractData(List contractProductModels) - { - DateTime expirationTime = DateTime.Now.AddMinutes(60); - CancellationChangeToken expirationToken = new CancellationChangeToken(new CancellationTokenSource(TimeSpan.FromMinutes(60)).Token); - MemoryCacheEntryOptions cacheEntryOptions = new MemoryCacheEntryOptions() - // Pin to cache. - .SetPriority(CacheItemPriority.NeverRemove) - // Set the actual expiration time - .SetAbsoluteExpiration(expirationTime) - // Force eviction to run - .AddExpirationToken(expirationToken); - - this.MemoryCacheService.Set("ContractProducts", contractProductModels, cacheEntryOptions); - } - + #endregion } \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/SupportRequestHandler.cs b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/SupportRequestHandler.cs index 8c6119aa..d1b4b88d 100644 --- a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/SupportRequestHandler.cs +++ b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/SupportRequestHandler.cs @@ -14,21 +14,23 @@ public class SupportRequestHandler : IRequestHandler { private readonly Func ConfigurationServiceResolver; private readonly IDatabaseContext DatabaseContext; - private readonly IMemoryCacheService MemoryCacheService; + + private readonly IApplicationCache ApplicationCache; + public SupportRequestHandler(Func configurationServiceResolver, IDatabaseContext databaseContext, - IMemoryCacheService memoryCacheService) + IApplicationCache applicationCache) { this.ConfigurationServiceResolver = configurationServiceResolver; this.DatabaseContext = databaseContext; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; } public async Task Handle(UploadLogsRequest request, CancellationToken cancellationToken) { while (true) { - var logEntries = await this.DatabaseContext.GetLogMessages(10); // TODO: Configurable batch size + List logEntries = await this.DatabaseContext.GetLogMessages(10); // TODO: Configurable batch size if (logEntries.Any() == false) { @@ -45,8 +47,8 @@ public async Task Handle(UploadLogsRequest request, CancellationToken c EntryDateTime = l.EntryDateTime, Id = l.Id })); - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); - var configurationService = this.ConfigurationServiceResolver(useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); + IConfigurationService configurationService = this.ConfigurationServiceResolver(useTrainingMode); await configurationService.PostDiagnosticLogs(request.DeviceIdentifier, logMessageModels, CancellationToken.None); // Clear the logs that have been uploaded diff --git a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs index d690b98e..a0795f41 100644 --- a/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs +++ b/TransactionMobile.Maui.BusinessLogic/RequestHandlers/TransactionRequestHandler.cs @@ -15,18 +15,20 @@ public class TransactionRequestHandler : IRequestHandler TransactionServiceResolver; private readonly IDatabaseContext DatabaseContext; - private readonly IMemoryCacheService MemoryCacheService; + + private readonly IApplicationCache ApplicationCache; + #endregion #region Constructors public TransactionRequestHandler(Func transactionServiceResolver, IDatabaseContext databaseContext, - IMemoryCacheService memoryCacheService) + IApplicationCache applicationCache) { this.TransactionServiceResolver = transactionServiceResolver; this.DatabaseContext = databaseContext; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; } #endregion @@ -34,9 +36,8 @@ public TransactionRequestHandler(Func transactionS #region Methods public async Task Handle(PerformMobileTopupRequest request, - CancellationToken cancellationToken) - { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + CancellationToken cancellationToken) { + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, useTrainingMode, cancellationToken); // TODO: Factory @@ -151,7 +152,7 @@ private async Task UpdateTransactionRecord(TransactionRecord transactionRecord, public async Task Handle(LogonTransactionRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, useTrainingMode, cancellationToken); // TODO: Factory @@ -176,7 +177,7 @@ public async Task Handle(LogonTransactionRequest requ public async Task Handle(PerformVoucherIssueRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); (TransactionRecord transactionRecord, Int64 transactionNumber) transaction = await this.CreateTransactionRecord(request, useTrainingMode, cancellationToken); // TODO: Factory PerformVoucherIssueRequestModel model = new PerformVoucherIssueRequestModel @@ -205,7 +206,7 @@ public async Task Handle(PerformVoucherIssueRequest request, public async Task Handle(PerformReconciliationRequest request, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + Boolean useTrainingMode = this.ApplicationCache.GetUseTrainingMode(); List storedTransactions = await this.DatabaseContext.GetTransactions(); diff --git a/TransactionMobile.Maui.BusinessLogic/Services/ApplicationCache.cs b/TransactionMobile.Maui.BusinessLogic/Services/ApplicationCache.cs new file mode 100644 index 00000000..9b03ab83 --- /dev/null +++ b/TransactionMobile.Maui.BusinessLogic/Services/ApplicationCache.cs @@ -0,0 +1,103 @@ +namespace TransactionMobile.Maui.BusinessLogic.Services +{ + using Microsoft.Extensions.Caching.Memory; + using Models; + + public class ApplicationCache : IApplicationCache + { + #region Fields + + private readonly IMemoryCache MemoryCache; + + #endregion + + #region Constructors + + public ApplicationCache(IMemoryCache memoryCache) { + this.MemoryCache = memoryCache; + } + + #endregion + + #region Methods + + public TokenResponseModel GetAccessToken() { + return this.TryGetValue("AccessToken"); + } + + public Configuration GetConfiguration() { + return this.TryGetValue("Configuration"); + } + + public List GetContractProducts() { + return this.TryGetValue>("ContractProducts"); + } + + public Guid GetEstateId() { + return this.TryGetValue("EstateId"); + } + + public Boolean GetIsLoggedIn() { + return this.TryGetValue("isLoggedIn"); + } + + public Guid GetMerchantId() { + return this.TryGetValue("MerchantId"); + } + + public Boolean GetUseTrainingMode() { + return this.TryGetValue("UseTrainingMode"); + } + + public void SetAccessToken(TokenResponseModel value, + MemoryCacheEntryOptions options = default) { + this.Set("AccessToken", value, options); + } + + public void SetConfiguration(Configuration value, + MemoryCacheEntryOptions options = default) { + this.Set("Configuration", value, options); + } + + public void SetContractProducts(List value, + MemoryCacheEntryOptions options = default) { + this.Set("ContractProducts", value, options); + } + + public void SetEstateId(Guid value, + MemoryCacheEntryOptions options = default) { + this.Set("EstateId", value, options); + } + + public void SetIsLoggedIn(Boolean value, + MemoryCacheEntryOptions options = default) { + this.Set("isLoggedIn", value, options); + } + + public void SetMerchantId(Guid value, + MemoryCacheEntryOptions options = default) { + this.Set("MerchantId", value, options); + } + + public void SetUseTrainingMode(Boolean value, + MemoryCacheEntryOptions options = default) { + this.Set("UseTrainingMode", value, options); + } + + private void Set(String key, + T cache, + MemoryCacheEntryOptions options) { + this.MemoryCache.Set(key, cache, options); + } + + private T TryGetValue(String Key) { + if (this.MemoryCache.TryGetValue(Key, out T cachedItem)) { + return cachedItem; + } + + return default; + } + + #endregion + } +} \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/Services/AuthenticationService.cs b/TransactionMobile.Maui.BusinessLogic/Services/AuthenticationService.cs index 47615ec7..89f536aa 100644 --- a/TransactionMobile.Maui.BusinessLogic/Services/AuthenticationService.cs +++ b/TransactionMobile.Maui.BusinessLogic/Services/AuthenticationService.cs @@ -16,12 +16,12 @@ public class AuthenticationService : IAuthenticationService { private readonly ISecurityServiceClient SecurityServiceClient; - private readonly IMemoryCacheService MemoryCacheService; + private readonly IApplicationCache ApplicationCache; - public AuthenticationService(ISecurityServiceClient securityServiceClient, IMemoryCacheService memoryCacheService) + public AuthenticationService(ISecurityServiceClient securityServiceClient, IApplicationCache applicationCache) { this.SecurityServiceClient = securityServiceClient; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; } public async Task GetToken(String username, @@ -30,7 +30,7 @@ public async Task GetToken(String username, { try { - this.MemoryCacheService.TryGetValue("Configuration", out Configuration configuration); + Configuration configuration = this.ApplicationCache.GetConfiguration(); //username = "merchantuser@v28emulatormerchant.co.uk"; //password = "123456"; @@ -63,7 +63,7 @@ public async Task GetToken(String username, public async Task RefreshAccessToken(String refreshToken, CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("Configuration", out Configuration configuration); + Configuration configuration = this.ApplicationCache.GetConfiguration(); try { Shared.Logger.Logger.LogInformation($"About to request refresh token"); diff --git a/TransactionMobile.Maui.BusinessLogic/Services/IApplicationCache.cs b/TransactionMobile.Maui.BusinessLogic/Services/IApplicationCache.cs new file mode 100644 index 00000000..72bc56d0 --- /dev/null +++ b/TransactionMobile.Maui.BusinessLogic/Services/IApplicationCache.cs @@ -0,0 +1,35 @@ +namespace TransactionMobile.Maui.BusinessLogic.Services; + +using Microsoft.Extensions.Caching.Memory; +using Models; + +public interface IApplicationCache +{ + Boolean GetUseTrainingMode(); + + void SetUseTrainingMode(Boolean value, MemoryCacheEntryOptions options = default); + + Boolean GetIsLoggedIn(); + + void SetIsLoggedIn(Boolean value, MemoryCacheEntryOptions options = default); + + Configuration GetConfiguration(); + + void SetConfiguration(Configuration value, MemoryCacheEntryOptions options = default); + + List GetContractProducts(); + + void SetContractProducts(List value, MemoryCacheEntryOptions options = default); + + TokenResponseModel GetAccessToken(); + + void SetAccessToken(TokenResponseModel value, MemoryCacheEntryOptions options = default); + + Guid GetEstateId(); + + void SetEstateId(Guid value, MemoryCacheEntryOptions options = default); + + Guid GetMerchantId(); + + void SetMerchantId(Guid value, MemoryCacheEntryOptions options = default); +} \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/Services/IMemoryCacheService.cs b/TransactionMobile.Maui.BusinessLogic/Services/IMemoryCacheService.cs deleted file mode 100644 index 639d3ff3..00000000 --- a/TransactionMobile.Maui.BusinessLogic/Services/IMemoryCacheService.cs +++ /dev/null @@ -1,51 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace TransactionMobile.Maui.BusinessLogic.Services -{ - using Microsoft.Extensions.Caching.Memory; - - public interface IMemoryCacheService - { - bool TryGetValue(string Key, out T cache); - void Set(string key, T cache); - - void Set(string key, - T cache, - MemoryCacheEntryOptions options); - } - - public class MemoryCacheService : IMemoryCacheService - { - private readonly IMemoryCache MemoryCache; - - public MemoryCacheService(IMemoryCache memoryCache) - { - this.MemoryCache = memoryCache; - } - - public void Set(string key, T cache) - { - this.Set(key, cache, default); - } - - public void Set(string key, T cache, MemoryCacheEntryOptions options) - { - this.MemoryCache.Set(key, cache, options); - } - - public bool TryGetValue(string Key, out T cache) - { - if (this.MemoryCache.TryGetValue(Key, out T cachedItem)) - { - cache = cachedItem; - return true; - } - cache = default(T); - return false; - } - } -} diff --git a/TransactionMobile.Maui.BusinessLogic/Services/MerchantService.cs b/TransactionMobile.Maui.BusinessLogic/Services/MerchantService.cs index cfbc3c0c..44175d68 100644 --- a/TransactionMobile.Maui.BusinessLogic/Services/MerchantService.cs +++ b/TransactionMobile.Maui.BusinessLogic/Services/MerchantService.cs @@ -9,20 +9,20 @@ public class MerchantService : IMerchantService { private readonly IEstateClient EstateClient; - private readonly IMemoryCacheService MemoryCacheService; - - public MerchantService(IEstateClient estateClient, IMemoryCacheService memoryCacheService) + private readonly IApplicationCache ApplicationCache; + + public MerchantService(IEstateClient estateClient, IApplicationCache applicationCache) { this.EstateClient = estateClient; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; } public async Task> GetContractProducts(CancellationToken cancellationToken) { List result = new List(); - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); - this.MemoryCacheService.TryGetValue("EstateId", out Guid estateId); - this.MemoryCacheService.TryGetValue("MerchantId", out Guid merchantId); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); + Guid estateId = this.ApplicationCache.GetEstateId(); + Guid merchantId = this.ApplicationCache.GetMerchantId(); Shared.Logger.Logger.LogInformation($"About to request merchant contracts"); Shared.Logger.Logger.LogDebug($"Merchant Contract Request details: Estate Id {estateId} Merchant Id {merchantId} Access Token {accessToken.AccessToken}"); @@ -90,9 +90,9 @@ private ProductType GetProductType(String operatorName) public async Task GetMerchantBalance(CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); - this.MemoryCacheService.TryGetValue("EstateId", out Guid estateId); - this.MemoryCacheService.TryGetValue("MerchantId", out Guid merchantId); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); + Guid estateId = this.ApplicationCache.GetEstateId(); + Guid merchantId = this.ApplicationCache.GetMerchantId(); Shared.Logger.Logger.LogInformation($"About to request merchant merchant balance"); Shared.Logger.Logger.LogDebug($"Merchant Balance Request details: Estate Id {estateId} Merchant Id {merchantId} Access Token {accessToken.AccessToken}"); diff --git a/TransactionMobile.Maui.BusinessLogic/Services/TransactionService.cs b/TransactionMobile.Maui.BusinessLogic/Services/TransactionService.cs index bc1a0ce9..df66f6f6 100644 --- a/TransactionMobile.Maui.BusinessLogic/Services/TransactionService.cs +++ b/TransactionMobile.Maui.BusinessLogic/Services/TransactionService.cs @@ -19,8 +19,8 @@ public class TransactionService : ClientProxyBase, ITransactionService { private readonly Func BaseAddressResolver; - private readonly IMemoryCacheService MemoryCacheService; - + private readonly IApplicationCache ApplicationCache; + private String BuildRequestUrl(String route) { String baseAddress = this.BaseAddressResolver("TransactionProcessorACL"); @@ -46,10 +46,10 @@ protected override async Task HandleResponse(HttpResponseMessage respons public TransactionService(Func baseAddressResolver, HttpClient httpClient, - IMemoryCacheService memoryCacheService) : base(httpClient) + IApplicationCache applicationCache) : base(httpClient) { this.BaseAddressResolver = baseAddressResolver; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; // Add the API version header this.HttpClient.DefaultRequestHeaders.Add("api-version", "1.0"); @@ -83,7 +83,7 @@ public async Task PerformLogon(PerformLogonRequestMod StringContent httpContent = new StringContent(requestSerialised, Encoding.UTF8, "application/json"); // Add the access token to the client headers - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); Shared.Logger.Logger.LogDebug($"Logon Transaction Request details: Uri {requestUri} Payload {requestSerialised} Access Token {accessToken.AccessToken}"); @@ -161,7 +161,7 @@ public async Task PerformMobileTopup(PerformMobileTopupRequestModel mod StringContent httpContent = new StringContent(requestSerialised, Encoding.UTF8, "application/json"); // Add the access token to the client headers - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); Shared.Logger.Logger.LogDebug($"Mobile Topup Transaction Request details: Uri {requestUri} Payload {requestSerialised} Access Token {accessToken.AccessToken}"); @@ -231,7 +231,7 @@ public async Task PerformReconciliation(PerformReconciliationRequestMod StringContent httpContent = new StringContent(requestSerialised, Encoding.UTF8, "application/json"); // Add the access token to the client headers - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); Shared.Logger.Logger.LogDebug($"Reconciliation Transaction Request details: Uri {requestUri} Payload {requestSerialised} Access Token {accessToken.AccessToken}"); @@ -301,7 +301,7 @@ public async Task PerformVoucherIssue(PerformVoucherIssueRequestModel m StringContent httpContent = new StringContent(requestSerialised, Encoding.UTF8, "application/json"); // Add the access token to the client headers - this.MemoryCacheService.TryGetValue("AccessToken", out TokenResponseModel accessToken); + TokenResponseModel accessToken = this.ApplicationCache.GetAccessToken(); Shared.Logger.Logger.LogDebug($"Voucher Transaction Request details: Uri {requestUri} Payload {requestSerialised} Access Token {accessToken.AccessToken}"); diff --git a/TransactionMobile.Maui.BusinessLogic/UIServices/IDialogService.cs b/TransactionMobile.Maui.BusinessLogic/UIServices/IDialogService.cs index bf68ee55..a0074055 100644 --- a/TransactionMobile.Maui.BusinessLogic/UIServices/IDialogService.cs +++ b/TransactionMobile.Maui.BusinessLogic/UIServices/IDialogService.cs @@ -14,16 +14,16 @@ Task ShowDialog(String title, String cancelString); Task ShowErrorToast(String message, - Action? action, - String? actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken); + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default); Task ShowInformationToast(String message, - Action? action, - String? actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken); + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default); Task ShowPrompt(String title, String message, @@ -35,10 +35,10 @@ Task ShowPrompt(String title, String initialValue = ""); Task ShowWarningToast(String message, - Action? action, - String? actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken); + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default); #endregion } \ No newline at end of file diff --git a/TransactionMobile.Maui.BusinessLogic/ViewModels/Admin/AdminPageViewModel.cs b/TransactionMobile.Maui.BusinessLogic/ViewModels/Admin/AdminPageViewModel.cs index 0d733305..5c525f2f 100644 --- a/TransactionMobile.Maui.BusinessLogic/ViewModels/Admin/AdminPageViewModel.cs +++ b/TransactionMobile.Maui.BusinessLogic/ViewModels/Admin/AdminPageViewModel.cs @@ -16,8 +16,6 @@ public class AdminPageViewModel : BaseViewModel private readonly INavigationService NavigationService; - private readonly IMemoryCacheService MemoryCacheService; - private readonly IDeviceService DeviceService; private readonly IApplicationInfoService ApplicationInfoService; @@ -25,12 +23,10 @@ public class AdminPageViewModel : BaseViewModel #region Constructors public AdminPageViewModel(IMediator mediator, INavigationService navigationService, - IMemoryCacheService memoryCacheService, IDeviceService deviceService, IApplicationInfoService applicationInfoService) { this.Mediator = mediator; this.NavigationService = navigationService; - this.MemoryCacheService = memoryCacheService; this.DeviceService = deviceService; this.ApplicationInfoService = applicationInfoService; this.ReconciliationCommand = new AsyncCommand(this.ReconciliationCommandExecute); diff --git a/TransactionMobile.Maui.BusinessLogic/ViewModels/HomePageViewModel.cs b/TransactionMobile.Maui.BusinessLogic/ViewModels/HomePageViewModel.cs index bd3bffb4..f263efda 100644 --- a/TransactionMobile.Maui.BusinessLogic/ViewModels/HomePageViewModel.cs +++ b/TransactionMobile.Maui.BusinessLogic/ViewModels/HomePageViewModel.cs @@ -12,22 +12,22 @@ public class HomePageViewModel : BaseViewModel { #region Fields - private readonly IDialogService DialogService; + private readonly IApplicationCache ApplicationCache; - private readonly IMemoryCacheService MemoryCacheService; + private readonly IDialogService DialogService; #endregion #region Constructors - public HomePageViewModel(IMemoryCacheService memoryCacheService, + public HomePageViewModel(IApplicationCache applicationCache, IDialogService dialogService) { - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; this.DialogService = dialogService; } public async Task ShowDebugMessage(String message) { - this.MemoryCacheService.TryGetValue("Configuration", out Configuration configuration); + Configuration configuration = this.ApplicationCache.GetConfiguration(); if (configuration.ShowDebugMessages) { @@ -40,7 +40,7 @@ public async Task ShowDebugMessage(String message) { #region Methods public async Task Initialise(CancellationToken cancellationToken) { - this.MemoryCacheService.TryGetValue("Configuration", out Configuration configuration); + Configuration configuration = this.ApplicationCache.GetConfiguration(); if (configuration.EnableAutoUpdates) { await Distribute.SetEnabledAsync(true); diff --git a/TransactionMobile.Maui.BusinessLogic/ViewModels/LoginPageViewModel.cs b/TransactionMobile.Maui.BusinessLogic/ViewModels/LoginPageViewModel.cs index b2a20f3d..32e883f2 100644 --- a/TransactionMobile.Maui.BusinessLogic/ViewModels/LoginPageViewModel.cs +++ b/TransactionMobile.Maui.BusinessLogic/ViewModels/LoginPageViewModel.cs @@ -17,12 +17,14 @@ public class LoginPageViewModel : BaseViewModel { private readonly INavigationService NavigationService; - private readonly IMemoryCacheService MemoryCacheService; - + private readonly IApplicationCache ApplicationCache; + private readonly IDeviceService DeviceService; private readonly IApplicationInfoService ApplicationInfoService; + private readonly IDialogService DialogService; + private String userName; private String password; @@ -31,13 +33,15 @@ public class LoginPageViewModel : BaseViewModel #region Constructors - public LoginPageViewModel(IMediator mediator, INavigationService navigationService, IMemoryCacheService memoryCacheService, - IDeviceService deviceService,IApplicationInfoService applicationInfoService) + public LoginPageViewModel(IMediator mediator, INavigationService navigationService, IApplicationCache applicationCache, + IDeviceService deviceService,IApplicationInfoService applicationInfoService, + IDialogService dialogService) { this.NavigationService = navigationService; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; this.DeviceService = deviceService; this.ApplicationInfoService = applicationInfoService; + this.DialogService = dialogService; this.LoginCommand = new AsyncCommand(this.LoginCommandExecute); this.Mediator = mediator; } @@ -72,60 +76,110 @@ public Boolean UseTrainingMode #region Methods - private async Task LoginCommandExecute() - { - Shared.Logger.Logger.LogInformation("LoginCommandExecute called"); - - this.MemoryCacheService.Set("UseTrainingMode", this.useTrainingMode); + private void CacheUseTrainingMode() => this.ApplicationCache.SetUseTrainingMode(this.useTrainingMode); - // TODO: this method needs refactored + private async Task GetConfiguration() { String deviceIdentifier = this.DeviceService.GetIdentifier(); GetConfigurationRequest getConfigurationRequest = GetConfigurationRequest.Create(deviceIdentifier); Configuration configuration = await this.Mediator.Send(getConfigurationRequest); - + + if (configuration == null) { + throw new ApplicationException("Error getting device configuration."); + } + // Cache the config object - this.MemoryCacheService.Set("Configuration", configuration); + this.ApplicationCache.SetConfiguration(configuration); + } + private async Task GetUserToken() { LoginRequest loginRequest = LoginRequest.Create(this.UserName, this.Password); TokenResponseModel token = await this.Mediator.Send(loginRequest); - //if (token == null) - //{ - // TODO: Some kind of error handling - //} + if (token == null) { + throw new ApplicationException($"Login failed for user {this.UserName}"); + } + // Cache the token this.CacheAccessToken(token); + } + private async Task PerformLogonTransaction() { // Logon Transaction - LogonTransactionRequest logonTransactionRequest = LogonTransactionRequest.Create(DateTime.Now, "1", + String deviceIdentifier = this.DeviceService.GetIdentifier(); + LogonTransactionRequest logonTransactionRequest = LogonTransactionRequest.Create(DateTime.Now, "1", deviceIdentifier, this.ApplicationInfoService.VersionString); PerformLogonResponseModel logonResponse = await this.Mediator.Send(logonTransactionRequest); if (logonResponse.IsSuccessful == false) { - // TODO: Throw an error here + throw new ApplicationException($"Error during Logon Transaction. Error Msg: {logonResponse.ResponseMessage}"); } - + // Set the user information - this.MemoryCacheService.Set("EstateId", logonResponse.EstateId); - this.MemoryCacheService.Set("MerchantId", logonResponse.MerchantId); + this.ApplicationCache.SetEstateId(logonResponse.EstateId); + this.ApplicationCache.SetMerchantId(logonResponse.MerchantId); + } + private async Task GetMerchantContractProducts() { // Get Contracts GetContractProductsRequest getContractProductsRequest = GetContractProductsRequest.Create(); - await this.Mediator.Send(getContractProductsRequest); - + List products = await this.Mediator.Send(getContractProductsRequest); + + if (products.Any() == false) + { + throw new ApplicationException($"Error getting contract products."); + } + + this.CacheContractData(products); + } + + private void CacheContractData(List contractProductModels) + { + DateTime expirationTime = DateTime.Now.AddMinutes(60); + CancellationChangeToken expirationToken = new CancellationChangeToken(new CancellationTokenSource(TimeSpan.FromMinutes(60)).Token); + MemoryCacheEntryOptions cacheEntryOptions = new MemoryCacheEntryOptions() + // Pin to cache. + .SetPriority(CacheItemPriority.NeverRemove) + // Set the actual expiration time + .SetAbsoluteExpiration(expirationTime) + // Force eviction to run + .AddExpirationToken(expirationToken); + + this.ApplicationCache.SetContractProducts(contractProductModels, cacheEntryOptions); + } + + private async Task GetMerchantBalance() { // Get the merchant balance // TODO: Cache the result, but will add this to a timer call to keep up to date... GetMerchantBalanceRequest getMerchantBalanceRequest = GetMerchantBalanceRequest.Create(); await this.Mediator.Send(getMerchantBalanceRequest); + } + + private async Task LoginCommandExecute() + { + try { + Shared.Logger.Logger.LogInformation("LoginCommandExecute called"); + + this.CacheUseTrainingMode(); - // TODO: Need to set the application as in training mode somehow + await this.GetConfiguration(); - this.MemoryCacheService.Set("IsLoggedIn", true); + await this.GetUserToken(); - await this.NavigationService.GoToHome(); + await this.PerformLogonTransaction(); + + await this.GetMerchantContractProducts(); + + await this.GetMerchantBalance(); + + this.ApplicationCache.SetIsLoggedIn(true); + await this.NavigationService.GoToHome(); + } + catch(ApplicationException aex) { + await this.DialogService.ShowWarningToast(aex.Message); + } } private async void AccessTokenExpired(Object key, @@ -159,7 +213,7 @@ private void CacheAccessToken(TokenResponseModel token) // Add eviction callback .RegisterPostEvictionCallback(callback:this.AccessTokenExpired); - this.MemoryCacheService.Set("AccessToken", token, cacheEntryOptions); + this.ApplicationCache.SetAccessToken(token, cacheEntryOptions); } #endregion diff --git a/TransactionMobile.Maui.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs b/TransactionMobile.Maui.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs index 1975b4ef..5ae481b0 100644 --- a/TransactionMobile.Maui.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs +++ b/TransactionMobile.Maui.BusinessLogic/ViewModels/MyAccount/MyAccountPageViewModel.cs @@ -10,15 +10,14 @@ public class MyAccountPageViewModel : BaseViewModel { private readonly INavigationService NavigationService; - private readonly IMemoryCacheService MemoryCacheService; + private readonly IApplicationCache ApplicationCache; #region Constructors - public MyAccountPageViewModel(INavigationService navigationService, - IMemoryCacheService memoryCacheService) + public MyAccountPageViewModel(INavigationService navigationService,IApplicationCache applicationCache) { this.NavigationService = navigationService; - this.MemoryCacheService = memoryCacheService; + this.ApplicationCache = applicationCache; this.LogoutCommand = new AsyncCommand(this.LogoutCommandExecute); this.Title = "My Account"; } @@ -36,7 +35,7 @@ public MyAccountPageViewModel(INavigationService navigationService, private async Task LogoutCommandExecute() { Shared.Logger.Logger.LogInformation("LogoutCommand called"); - this.MemoryCacheService.Set("AccessToken", null); + this.ApplicationCache.SetAccessToken(null); await this.NavigationService.GoToLoginPage(); } diff --git a/TransactionMobile.Maui/App.xaml.cs b/TransactionMobile.Maui/App.xaml.cs index 12cb5d6a..53391e7d 100644 --- a/TransactionMobile.Maui/App.xaml.cs +++ b/TransactionMobile.Maui/App.xaml.cs @@ -23,9 +23,9 @@ public App() { if (view is TitleLabel) { - var memoryCache = MauiProgram.Container.Services.GetService(); + var applicationCache = MauiProgram.Container.Services.GetService(); - memoryCache.TryGetValue("UseTrainingMode", out Boolean useTrainingMode); + Boolean useTrainingMode = applicationCache.GetUseTrainingMode(); if (useTrainingMode) { @@ -126,15 +126,15 @@ public App() }); #endif - var memoryCache = MauiProgram.Container.Services.GetService(); - memoryCache.TryGetValue("isLoggedIn", out bool isLoggedIn); + IApplicationCache applicationCache = MauiProgram.Container.Services.GetService(); + Boolean isLoggedIn = applicationCache.GetIsLoggedIn(); if (isLoggedIn) { MainPage = new AppShell(); } else { - var loginPageViewModel = MauiProgram.Container.Services.GetService(); + LoginPageViewModel loginPageViewModel = MauiProgram.Container.Services.GetService(); MainPage = new LoginPage(loginPageViewModel); } diff --git a/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs b/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs index 97f33c6a..c8580f61 100644 --- a/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs +++ b/TransactionMobile.Maui/Extensions/MauiAppBuilderExtensions.cs @@ -65,12 +65,12 @@ public static MauiAppBuilder ConfigureAppServices(this MauiAppBuilder builder) { return "https://5r8nmm.deta.dev"; } - IMemoryCacheService memoryCacheService = MauiProgram.Container.Services - .GetService(); + IApplicationCache applicationCache = MauiProgram.Container.Services + .GetService(); - Boolean configFound = memoryCacheService.TryGetValue("Configuration", out Configuration configuration); + Configuration configuration = applicationCache.GetConfiguration(); - if (configFound && configuration != null) + if (configuration != null) { if (configSetting == "SecurityService") { @@ -153,7 +153,7 @@ public static MauiAppBuilder ConfigureAppServices(this MauiAppBuilder builder) { builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder; } diff --git a/TransactionMobile.Maui/UIServices/DialogService.cs b/TransactionMobile.Maui/UIServices/DialogService.cs index 2868f5e9..442c66f0 100644 --- a/TransactionMobile.Maui/UIServices/DialogService.cs +++ b/TransactionMobile.Maui/UIServices/DialogService.cs @@ -2,6 +2,7 @@ { using BusinessLogic.UIServices; using CommunityToolkit.Maui.Alerts; + using CommunityToolkit.Maui.Core; public class DialogService : IDialogService { @@ -21,23 +22,25 @@ public async Task ShowDialog(String title, } public async Task ShowErrorToast(String message, - Action action, - String actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken) { + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default) + { await Application.Current.MainPage.DisplaySnackbar(message, action, actionButtonText, duration, - SnackBarOptionsHelper.GetInfoSnackbarOptions, + SnackBarOptionsHelper.GetErrorSnackbarOptions, cancellationToken); } public async Task ShowInformationToast(String message, - Action action, - String actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken) { + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default) + { await Application.Current.MainPage.DisplaySnackbar(message, action, actionButtonText, @@ -58,15 +61,20 @@ public async Task ShowPrompt(String title, } public async Task ShowWarningToast(String message, - Action action, - String actionButtonText, - TimeSpan? duration, - CancellationToken cancellationToken) { + Action? action = null, + String? actionButtonText = "OK", + TimeSpan? duration = null, + CancellationToken cancellationToken = default) + { + if (duration == null) + { + duration = TimeSpan.FromSeconds(10); + } await Application.Current.MainPage.DisplaySnackbar(message, action, actionButtonText, duration, - SnackBarOptionsHelper.GetInfoSnackbarOptions, + SnackBarOptionsHelper.GetWarningSnackbarOptions, cancellationToken); }