From f004c8205a0a0c721a8a70fb7de587211dd95c61 Mon Sep 17 00:00:00 2001 From: Zeeshaun Date: Wed, 11 Mar 2026 13:21:47 -0500 Subject: [PATCH] Adding MaidBotApi --- LCU.API.Internal.MaidBotApi/.dockerignore | 17 + LCU.API.Internal.MaidBotApi/.gitignore | 330 ++++++++++++++++++ LCU.API.Internal.MaidBotApi/Dockerfile | 49 +++ .../LCU.Api.Internal.MaidBot.sln | 54 +++ .../Configurations/ApiConfiguration.cs | 14 + .../Configurations/FeatureFlags.cs | 7 + .../Consumers/LoggingEventConsumer.cs | 40 +++ .../Controllers/EventLogController.cs | 73 ++++ .../Controllers/LoggingMatrixController.cs | 109 ++++++ .../Controllers/QueueEventLogController.cs | 45 +++ .../Controllers/StatusController.cs | 34 ++ .../DataAccesses/INotificationsApiDao.cs | 8 + .../DataAccesses/NotificationsApiDao.cs | 23 ++ .../EnvironmentView/EnvironmentView.cs | 35 ++ .../EnvironmentView/IEnvironmentView.cs | 16 + .../Exceptions/NotFoundException.cs | 15 + .../Exceptions/ServerErrorException.cs | 14 + .../HostedService/SchedulerHostedService.cs | 66 ++++ .../LCU.Api.Internal.MaidBotApi.csproj | 47 +++ .../LCU.Api.Internal.MaidBotApi.xml | 17 + .../LCU.Api.Internal.MaidBotApi/Program.cs | 207 +++++++++++ .../Security/AzureActiveDirectoryOptions.cs | 13 + .../AzureAdServiceCollectionExtensions.cs | 52 +++ .../Services/DebugEventLogService.cs | 46 +++ .../Services/EventLogService.cs | 87 +++++ .../Services/IDebugEventLogService.cs | 9 + .../Services/IEventLogService.cs | 12 + .../Services/ILogDistributionService.cs | 7 + .../Services/ILoggingMatrixService.cs | 17 + .../Services/INotificationsApiService.cs | 9 + .../Services/IQueueEventLogService.cs | 8 + .../Services/LogDistributionService.cs | 59 ++++ .../Services/LoggingMatrixService.cs | 140 ++++++++ .../Services/NotificationsApiService.cs | 78 +++++ .../Services/QueueEventLogService.cs | 36 ++ .../Templates/LogEmailRowTemplate.html | 4 + .../Templates/LogEmailTemplate.html | 56 +++ .../appsettings.json | 38 ++ .../LCU.Api.Internal.MaidBotLib.csproj | 25 ++ .../Models/DebugEventLog.cs | 20 ++ .../Models/EventLog.cs | 16 + .../Models/GroupEnum.cs | 14 + .../Models/LoggingMatrix.cs | 18 + .../Models/PropertyEnum.cs | 7 + .../Persistence/AppDbContext.cs | 23 ++ .../Repositories/BaseRepository.cs | 17 + .../Repositories/DebugEventLogRepository.cs | 20 ++ .../Repositories/EventLogRepository.cs | 29 ++ .../Repositories/IDebugEventLogRepository.cs | 13 + .../Repositories/IEventLogRepository.cs | 13 + .../Repositories/ILoggingMatrixRepository.cs | 19 + .../Repositories/IUnitOfWork.cs | 10 + .../Repositories/LoggingMatrixRepository.cs | 59 ++++ .../Repositories/UnitOfWork.cs | 25 ++ .../LCU.Api.Internal.MaidBotSeqApp.csproj | 42 +++ .../SeqToRabbit.cs | 100 ++++++ .../DebugEventLog.sql | 5 + .../LCU.Api.Internal.MaidBotSql/EventLog.sql | 11 + .../LCU.Api.Internal.MaidBotSql.refactorlog | 45 +++ .../LCU.Api.Internal.MaidBotSql.sqlproj | 68 ++++ .../LoggingMatrix.sql | 9 + .../LoggingMatrixControllerTest.cs | 138 ++++++++ .../QueueEventLogControllerTest.cs | 39 +++ .../LCU.Api.Internal.MaidBotTests.csproj | 27 ++ .../ModelTest/DebugEventLogTest.cs | 21 ++ .../RepositoryTests/DbContextFromJson.cs | 70 ++++ .../LoggingMatrixRepositoryTest.cs | 66 ++++ .../LoggingMatrixTestData.json | 52 +++ .../ServiceTests/DebugEventLogServiceTest.cs | 85 +++++ .../ServiceTests/EventLogServiceTest.cs | 170 +++++++++ .../LogDistributionServiceTest.cs | 130 +++++++ .../ServiceTests/LoggingMatrixServiceTest.cs | 106 ++++++ .../additional_test_args.runsettings | 27 ++ LCU.API.Internal.MaidBotApi/README.md | 41 +++ .../azdo_pipelines/azure-k8s-pipeline.yaml | 74 ++++ .../azure-pipelines-feature-branches.yaml | 10 + .../azdo_pipelines/azure-pipelines-prd.yaml | 9 + .../azdo_pipelines/azure-pipelines-qa.yaml | 9 + .../azdo_pipelines/azure-pipelines-uat.yaml | 9 + .../config-files/prd-pvars.yaml | 12 + .../azdo_pipelines/config-files/qa-pvars.yaml | 12 + .../config-files/uat-pvars.yaml | 12 + .../azure-pipelines.yml | 79 +++++ .../kustomize/base/Deployment.yaml | 46 +++ .../kustomize/base/Service.yaml | 11 + .../kustomize/base/kustomization.yaml | 9 + .../base/secrets-provider-class.yaml | 11 + .../kustomize/base/virtual-service.yaml | 19 + .../keyvaults/normal/kustomization.yaml | 10 + .../normal/set_secrets_deployment.yaml | 41 +++ .../normal/set_secrets_provider.yaml | 20 ++ .../normal/appsettings/appsettings.json | 2 + .../workloads/normal/kustomization.yaml | 40 +++ .../normal/set_appsettings_deployment.yaml | 12 + .../overlays/local/common/kustomization.yaml | 8 + .../common/set_appsettings_deployment.yaml | 12 + .../common/set_secrets_provider_class.yaml | 9 + .../overlays/local/kustomization.yaml | 2 + .../overlays/local/normal/configmap.yaml | 19 + .../overlays/local/normal/kustomization.yaml | 5 + .../local/normal/set_virtual_service.yaml | 8 + .../overlays/prd/appsettings/appsettings.json | 27 ++ .../overlays/prd/component/kustomization.yaml | 7 + .../component/set_secrets_provider_class.yaml | 7 + .../kustomize/overlays/prd/kustomization.yaml | 14 + .../overlays/prd/normal/kustomization.yaml | 12 + .../prd/normal/set_virtual_service.yaml | 3 + .../prd/set_configmap_deployment.yaml | 12 + .../overlays/qa/appsettings/appsettings.json | 27 ++ .../overlays/qa/component/kustomization.yaml | 7 + .../component/set_secrets_provider_class.yaml | 7 + .../kustomize/overlays/qa/kustomization.yaml | 14 + .../overlays/qa/normal/kustomization.yaml | 12 + .../qa/normal/set_virtual_service.yaml | 3 + .../overlays/qa/set_configmap_deployment.yaml | 12 + .../overlays/uat/appsettings/appsettings.json | 27 ++ .../overlays/uat/component/kustomization.yaml | 7 + .../component/set_secrets_provider_class.yaml | 7 + .../kustomize/overlays/uat/kustomization.yaml | 14 + .../overlays/uat/normal/kustomization.yaml | 12 + .../uat/normal/set_virtual_service.yaml | 3 + .../uat/set_configmap_deployment.yaml | 12 + 122 files changed, 4227 insertions(+) create mode 100644 LCU.API.Internal.MaidBotApi/.dockerignore create mode 100644 LCU.API.Internal.MaidBotApi/.gitignore create mode 100644 LCU.API.Internal.MaidBotApi/Dockerfile create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBot.sln create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/ApiConfiguration.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/FeatureFlags.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Consumers/LoggingEventConsumer.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/EventLogController.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/LoggingMatrixController.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/QueueEventLogController.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/StatusController.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/INotificationsApiDao.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/NotificationsApiDao.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/EnvironmentView.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/IEnvironmentView.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/NotFoundException.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/ServerErrorException.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/HostedService/SchedulerHostedService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.xml create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Program.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureActiveDirectoryOptions.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureAdServiceCollectionExtensions.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/DebugEventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/EventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IDebugEventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IEventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILogDistributionService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILoggingMatrixService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/INotificationsApiService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IQueueEventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LogDistributionService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LoggingMatrixService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/NotificationsApiService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/QueueEventLogService.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailRowTemplate.html create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailTemplate.html create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/appsettings.json create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/LCU.Api.Internal.MaidBotLib.csproj create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/DebugEventLog.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/EventLog.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/GroupEnum.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/LoggingMatrix.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/PropertyEnum.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Persistence/AppDbContext.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/BaseRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/DebugEventLogRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/EventLogRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IDebugEventLogRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IEventLogRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/ILoggingMatrixRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IUnitOfWork.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/LoggingMatrixRepository.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/UnitOfWork.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/LCU.Api.Internal.MaidBotSeqApp.csproj create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/SeqToRabbit.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/DebugEventLog.sql create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/EventLog.sql create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.refactorlog create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.sqlproj create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LoggingMatrix.sql create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/LoggingMatrixControllerTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/QueueEventLogControllerTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/LCU.Api.Internal.MaidBotTests.csproj create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ModelTest/DebugEventLogTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/DbContextFromJson.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixRepositoryTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixTestData.json create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/DebugEventLogServiceTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/EventLogServiceTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LogDistributionServiceTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LoggingMatrixServiceTest.cs create mode 100644 LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/additional_test_args.runsettings create mode 100644 LCU.API.Internal.MaidBotApi/README.md create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-k8s-pipeline.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-feature-branches.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-prd.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-qa.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-uat.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/prd-pvars.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/qa-pvars.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/uat-pvars.yaml create mode 100644 LCU.API.Internal.MaidBotApi/azure-pipelines.yml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/base/Deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/base/Service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/base/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/base/secrets-provider-class.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/base/virtual-service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_provider.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/appsettings/appsettings.json create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/set_appsettings_deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_appsettings_deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_secrets_provider_class.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/configmap.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/set_virtual_service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/appsettings/appsettings.json create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/set_secrets_provider_class.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/set_virtual_service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/set_configmap_deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/appsettings/appsettings.json create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/set_secrets_provider_class.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/set_virtual_service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/set_configmap_deployment.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/appsettings/appsettings.json create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/set_secrets_provider_class.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/kustomization.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/set_virtual_service.yaml create mode 100644 LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/set_configmap_deployment.yaml diff --git a/LCU.API.Internal.MaidBotApi/.dockerignore b/LCU.API.Internal.MaidBotApi/.dockerignore new file mode 100644 index 0000000..186c6b6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/.dockerignore @@ -0,0 +1,17 @@ +**/*.bat +**/*.log +**/*.md +**/*.yml +**/.dockerignore +**/.editorconfig +**/.git +**/.gitattributes +**/.gitignore +**/.vs +**/.vscode +**/bin +**/dist +**/dockerfile +**/node_modules +**/obj +**/package-lock.json diff --git a/LCU.API.Internal.MaidBotApi/.gitignore b/LCU.API.Internal.MaidBotApi/.gitignore new file mode 100644 index 0000000..3e759b7 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/.gitignore @@ -0,0 +1,330 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ diff --git a/LCU.API.Internal.MaidBotApi/Dockerfile b/LCU.API.Internal.MaidBotApi/Dockerfile new file mode 100644 index 0000000..dffcf56 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/Dockerfile @@ -0,0 +1,49 @@ +# .NET Core SDK +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src + +# Copy Projects +COPY LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj LCU.Api.Internal.MaidBotApi/ +COPY LCU.Api.Internal.MaidBotLib/LCU.Api.Internal.MaidBotLib.csproj LCU.Api.Internal.MaidBotLib/ + +# Configure NuGet auth for the Azure DevOps feed during restore. +ARG PAT=bh2lq3jibktw67b2wdbqyfln7cd3je6lk52kijntpj43v6kimpgq +RUN mkdir -p /root/.nuget/NuGet && \ + printf '%s\n' \ + '' \ + '' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + ' ' \ + '' \ + > /root/.nuget/NuGet/NuGet.Config +RUN dotnet restore LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj + +# Copy All Files +COPY . . + +FROM build AS test +LABEL test=true +RUN dotnet test -c Release --results-directory /testresults --logger "trx;LogFileName=test_results.trx" LCU.Api.Internal.MaidBotTests/LCU.Api.Internal.MaidBotTests.csproj + +# .NET Core Publish +FROM build AS publish +RUN dotnet publish LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj -c Release -o /app/publish + +# ASP.NET Core +FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine3.20 +RUN apk add --no-cache icu-libs && apk add --no-cache tzdata; +ENV TZ America/Chicago +ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false +ENV ASPNETCORE_ENVIRONMENT=Development + +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "LCU.Api.Internal.MaidBotApi.dll"] diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBot.sln b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBot.sln new file mode 100644 index 0000000..5eaf0b0 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBot.sln @@ -0,0 +1,54 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29905.134 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.Api.Internal.MaidBotApi", "LCU.API.Internal.MaidBotApi\LCU.Api.Internal.MaidBotApi.csproj", "{1C92A326-91A3-4904-B3EF-B766E10E7191}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.Api.Internal.MaidBotTests", "LCU.Api.Internal.MaidBotTests\LCU.Api.Internal.MaidBotTests.csproj", "{98503299-44F3-410A-B61F-36BC1706F132}" + ProjectSection(ProjectDependencies) = postProject + {1C92A326-91A3-4904-B3EF-B766E10E7191} = {1C92A326-91A3-4904-B3EF-B766E10E7191} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.Api.Internal.MaidBotSeqApp", "LCU.Api.Internal.MaidBotSeqApp\LCU.Api.Internal.MaidBotSeqApp.csproj", "{4E8E9B2F-69AD-4326-BD7E-DC53372C2092}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LCU.Api.Internal.MaidBotLib", "LCU.Api.Internal.MaidBotLib\LCU.Api.Internal.MaidBotLib.csproj", "{6FE57F07-EFA9-4769-AE61-95C72787AA9D}" +EndProject +Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "LCU.Api.Internal.MaidBotSql", "LCU.Api.Internal.MaidBotSql\LCU.Api.Internal.MaidBotSql.sqlproj", "{ECCE6677-A2F2-4694-964F-F91EBE7AAC00}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1C92A326-91A3-4904-B3EF-B766E10E7191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C92A326-91A3-4904-B3EF-B766E10E7191}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C92A326-91A3-4904-B3EF-B766E10E7191}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C92A326-91A3-4904-B3EF-B766E10E7191}.Release|Any CPU.Build.0 = Release|Any CPU + {98503299-44F3-410A-B61F-36BC1706F132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {98503299-44F3-410A-B61F-36BC1706F132}.Debug|Any CPU.Build.0 = Debug|Any CPU + {98503299-44F3-410A-B61F-36BC1706F132}.Release|Any CPU.ActiveCfg = Release|Any CPU + {98503299-44F3-410A-B61F-36BC1706F132}.Release|Any CPU.Build.0 = Release|Any CPU + {4E8E9B2F-69AD-4326-BD7E-DC53372C2092}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4E8E9B2F-69AD-4326-BD7E-DC53372C2092}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4E8E9B2F-69AD-4326-BD7E-DC53372C2092}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4E8E9B2F-69AD-4326-BD7E-DC53372C2092}.Release|Any CPU.Build.0 = Release|Any CPU + {6FE57F07-EFA9-4769-AE61-95C72787AA9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FE57F07-EFA9-4769-AE61-95C72787AA9D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FE57F07-EFA9-4769-AE61-95C72787AA9D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FE57F07-EFA9-4769-AE61-95C72787AA9D}.Release|Any CPU.Build.0 = Release|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Release|Any CPU.Build.0 = Release|Any CPU + {ECCE6677-A2F2-4694-964F-F91EBE7AAC00}.Release|Any CPU.Deploy.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {56A51B7E-A90A-4BFF-85D1-19ECB769AF6A} + EndGlobalSection +EndGlobal diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/ApiConfiguration.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/ApiConfiguration.cs new file mode 100644 index 0000000..af497f8 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/ApiConfiguration.cs @@ -0,0 +1,14 @@ +namespace LCU.Api.Internal.MaidBotApi.Configurations; + +public class ApiConfiguration +{ + public string AppName { get; set; } + public string SeqUrl { get; set; } + public string SeqApiKey { get; set; } + public string NotificationsApiEmail { get; set; } + public string BatchSchedulerCron { get; set; } + public FeatureFlags FeatureFlags { get; set; } + public string[] CorsAllowedOrigins { get; set; } + public string LogEmailTemplate { get; set; } + public string LogEmailRowTemplate { get; set; } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/FeatureFlags.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/FeatureFlags.cs new file mode 100644 index 0000000..0279019 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Configurations/FeatureFlags.cs @@ -0,0 +1,7 @@ +namespace LCU.Api.Internal.MaidBotApi.Configurations; + +public class FeatureFlags +{ + public bool LoggingEventConsumer { get; set; } + public bool RunScheduler { get; set; } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Consumers/LoggingEventConsumer.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Consumers/LoggingEventConsumer.cs new file mode 100644 index 0000000..bc62007 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Consumers/LoggingEventConsumer.cs @@ -0,0 +1,40 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using MassTransit; +using Serilog; +using LCU.Library.Internal.Exceptions; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotApi.Services; +namespace LCU.Api.Internal.MaidBotApi.Consumers; + +public class LoggingEventConsumer : IConsumer +{ + private readonly IServiceScopeFactory _scopeFactory; + + public LoggingEventConsumer(IServiceScopeFactory scopeFactory) + { + _scopeFactory = scopeFactory; + } + + public async Task Consume(ConsumeContext context) + { + try + { + using var scope = _scopeFactory.CreateScope(); + await Task.Run(async () => await scope.ServiceProvider.GetRequiredService().HandleIncomingEventLog(context.Message)); + } + catch (ServiceException serviceException) + { + Log.Fatal(serviceException, $"Handle Incoming EventLog Failure. " + + $"The Handle Incoming EventLog is placed on LCU.MaidBot_error."); + throw; + } + catch (Exception exception) + { + Log.Fatal(exception, $"Unexpected Handle Incoming EventLog Failure. " + + $"The Handle Incoming EventLog is placed on LCU.MaidBot_error."); + throw; + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/EventLogController.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/EventLogController.cs new file mode 100644 index 0000000..e97d563 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/EventLogController.cs @@ -0,0 +1,73 @@ +using System; +using System.Threading.Tasks; +using System.Linq; +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Serilog; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Library.Internal.Exceptions; +namespace LCU.API.Internal.MaidBotApi.Controllers; + +[ApiController] +[Route("api/[controller]")] + +public class EventLogController : ControllerBase +{ + private readonly IEventLogService _eventLogService; + + public EventLogController(IEventLogService eventLogService) + { + _eventLogService = eventLogService; + } + + [HttpGet] + [ProducesResponseType(200)] + [ProducesResponseType(204)] + [ProducesResponseType(typeof(EventLog), 400)] + [ProducesResponseType(500)] + public async Task Get() + { + try + { + var results = await _eventLogService.GetAsync(); + if (results == null || !results.Any()) + { + return NoContent(); + } + + return Ok(results); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + + [HttpDelete()] + [ProducesResponseType(200)] + [ProducesResponseType(500)] + public IActionResult DeleteMany([FromBody] List eventLogs) + { + try + { + _eventLogService.DeleteMany(eventLogs); + return Ok(); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/LoggingMatrixController.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/LoggingMatrixController.cs new file mode 100644 index 0000000..ce4023f --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/LoggingMatrixController.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Serilog; +using LCU.Api.Internal.MaidBotApi.Exceptions; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Library.Internal.Exceptions; +namespace LCU.API.Internal.MaidBotApi.Controllers; + +[ApiController] +[Route("api/[controller]")] + +public class LoggingMatrixController : ControllerBase +{ + private readonly ILoggingMatrixService _loggingMatrixService; + + public LoggingMatrixController(ILoggingMatrixService loggingMatrixService) + { + _loggingMatrixService = loggingMatrixService; + } + + [HttpGet(Name = "GetAllLoggingMatrixes")] + [ProducesResponseType(typeof(IEnumerable), 200)] + [ProducesResponseType(500)] + public async Task Get() + { + try + { + var result = await _loggingMatrixService.GetAsync(); + return Ok(result); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + + [HttpPost] + [ProducesResponseType(typeof(LoggingMatrix), 201)] + [ProducesResponseType(typeof(List), 400)] + [ProducesResponseType(500)] + public async Task Post([FromBody] LoggingMatrix loggingMatrix) + { + try + { + var result = await _loggingMatrixService.SaveAsync(loggingMatrix); + + if (result == null) + { + Log.Error($"Result is null could not create Logging Matrix"); + return StatusCode((StatusCodes.Status400BadRequest), "Could not create Logging Matrix."); + } + + return StatusCode(StatusCodes.Status201Created, result); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } + + [HttpPut] + [ProducesResponseType(typeof(LoggingMatrix), 200)] + [ProducesResponseType(400)] + [ProducesResponseType(404)] + [ProducesResponseType(500)] + public async Task Put([FromBody] LoggingMatrix loggingMatrix) + { + try + { + if (loggingMatrix.LoggingMatrixId <= 0) + { + return BadRequest("Invalid ID"); + } + + var result = await _loggingMatrixService.UpdateAsync(loggingMatrix); + + if(result == null) + { + return NotFound($"The LoggingMatrix with LoggingMatrixId: {loggingMatrix.LoggingMatrixId} " + + "could not be found"); + } + + return Ok(result); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/QueueEventLogController.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/QueueEventLogController.cs new file mode 100644 index 0000000..a425bda --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/QueueEventLogController.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Serilog; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Library.Internal.Exceptions; +namespace LCU.API.Internal.MaidBotApi.Controllers; + +[ApiController] +[Route("api/[controller]")] + +public class QueueEventLogController : ControllerBase +{ + private readonly IQueueEventLogService _queueEventLogService; + + public QueueEventLogController(IQueueEventLogService queueEventLogService) + { + _queueEventLogService = queueEventLogService; + } + + [HttpPost] + [ProducesResponseType(202)] + [ProducesResponseType(typeof(List), 400)] + [ProducesResponseType(500)] + public async Task Post([FromBody] EventLog EventLog) + { + try + { + await _queueEventLogService.QueueEventLog(EventLog); + return Accepted(); + } + catch (ServiceException exception) + { + return StatusCode(StatusCodes.Status500InternalServerError, exception.Message); + } + catch (Exception exception) + { + Log.Error(exception, "Unexpected Exception"); + return StatusCode(StatusCodes.Status500InternalServerError); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/StatusController.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/StatusController.cs new file mode 100644 index 0000000..89d71ad --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Controllers/StatusController.cs @@ -0,0 +1,34 @@ +using System; +using Microsoft.AspNetCore.Mvc; +using Serilog; +using LCU.Api.Internal.MaidBotApi.EnvironmentView; +namespace LCU.API.Internal.MaidBotApi.Controllers; + +[ApiController] +[Route("api/[controller]")] + +public class StatusController : ControllerBase +{ + private readonly IEnvironmentView _environmentView; + + public StatusController(IEnvironmentView environmentView) + { + _environmentView = environmentView; + } + + [HttpGet()] + [ProducesResponseType(200)] + [ProducesResponseType(500)] + public IActionResult Get() + { + try + { + return Ok(_environmentView); + } + catch (Exception ex) + { + Log.Error(ex, "Failure to return status"); + return StatusCode((int)System.Net.HttpStatusCode.InternalServerError); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/INotificationsApiDao.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/INotificationsApiDao.cs new file mode 100644 index 0000000..596127a --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/INotificationsApiDao.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; +using LCU.Shared.Common.NotificationApiLib.Models; +namespace LCU.Api.Internal.MaidBotApi.DataAccesses; + +public interface INotificationsApiDao +{ + Task SendEmailRequest(EmailRequest emailRequest); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/NotificationsApiDao.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/NotificationsApiDao.cs new file mode 100644 index 0000000..e37352b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/DataAccesses/NotificationsApiDao.cs @@ -0,0 +1,23 @@ +using System; +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotApi.Configurations; +using LCU.Library.Internal.LcuHttpClient.HttpRequest; +using LCU.Shared.Common.NotificationApiLib.Models; +namespace LCU.Api.Internal.MaidBotApi.DataAccesses; + +public class NotificationsApiDao : INotificationsApiDao +{ + private readonly ApiConfiguration _apiConfiguration; + private readonly IPostRequest _postRequest; + + public NotificationsApiDao(ApiConfiguration apiConfiguration, IPostRequest postRequest) + { + _apiConfiguration = apiConfiguration; + _postRequest = postRequest; + } + + public async Task SendEmailRequest(EmailRequest emailRequest) + { + await _postRequest.Async(new Uri(_apiConfiguration.NotificationsApiEmail), emailRequest); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/EnvironmentView.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/EnvironmentView.cs new file mode 100644 index 0000000..f1ccfd9 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/EnvironmentView.cs @@ -0,0 +1,35 @@ +using System; +using System.Reflection; +using Microsoft.AspNetCore.Hosting; +namespace LCU.Api.Internal.MaidBotApi.EnvironmentView; + +public class EnvironmentView : IEnvironmentView +{ + public string Application => _env.ApplicationName; + public DateTime CurrentDate => DateTime.Now; + public string BuildVersion => AssembleBuildVersion(); + public DateTime BuildDate => AssemblyBuildDate(); + public string Environment => _env.EnvironmentName; + private readonly IWebHostEnvironment _env; + + public EnvironmentView(IWebHostEnvironment env) + { + _env = env; + } + + public static DateTime AssemblyBuildDate() + { + //https://stackoverflow.com/a/804310/266594 + System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly(); + System.IO.FileInfo fileInfo = new System.IO.FileInfo(assembly.Location); + DateTime lastModified = fileInfo.LastWriteTime; + + return lastModified; + } + + public static string AssembleBuildVersion() + { + var version = Assembly.GetExecutingAssembly().GetName().Version; + return version == null ? "-.-.-" : version.ToString(); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/IEnvironmentView.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/IEnvironmentView.cs new file mode 100644 index 0000000..3f9fd9b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/EnvironmentView/IEnvironmentView.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotApi.EnvironmentView +{ + public interface IEnvironmentView + { + string Application { get; } + DateTime CurrentDate { get; } + string BuildVersion { get; } + DateTime BuildDate { get; } + string Environment { get; } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/NotFoundException.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/NotFoundException.cs new file mode 100644 index 0000000..368148e --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/NotFoundException.cs @@ -0,0 +1,15 @@ +using System; + +namespace LCU.Api.Internal.MaidBotApi.Exceptions +{ + /** + * If an entity cannot be found, that specific error can allow for a 404 or 400 with more detail to be + * returned. So specify that to the API layer. + */ + public class NotFoundException : ApplicationException + { + public NotFoundException(string message) : base(message) + { + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/ServerErrorException.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/ServerErrorException.cs new file mode 100644 index 0000000..46427f4 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Exceptions/ServerErrorException.cs @@ -0,0 +1,14 @@ +using System; + +namespace LCU.Api.Internal.MaidBotApi.Exceptions +{ + /** + * Do not want to expose database and related exceptions to the controllers / web layer. + * The lower layers log what happened for developers, then return a general error; unless + * a more specific error can be returned in a way to allow the client to act (such as NotFound). + */ + public class ServerErrorException : Exception + { + public ServerErrorException() : base("A server error occured, and a response could not be produced.") { } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/HostedService/SchedulerHostedService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/HostedService/SchedulerHostedService.cs new file mode 100644 index 0000000..7d4125f --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/HostedService/SchedulerHostedService.cs @@ -0,0 +1,66 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using Serilog; +using NCrontab; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotApi.Configurations; +namespace LCU.API.Internal.MaidBotApi.HostedService; + +public class SchedulerHostedService : BackgroundService +{ + private readonly ApiConfiguration _apiConfiguration; + private readonly IServiceScopeFactory _scopeFactory; + + private readonly CrontabSchedule _schedule; + private DateTime _nextScheduleRun; + public const string DefaultScheduleCronPattern = "*/5 * * * *"; + + private CancellationToken _cancellationToken; + + public SchedulerHostedService(IServiceScopeFactory scopeFactory, + ApiConfiguration apiConfiguration) + { + _scopeFactory = scopeFactory; + _apiConfiguration = apiConfiguration; + + var cron = (_apiConfiguration?.BatchSchedulerCron) ?? DefaultScheduleCronPattern; + _schedule = CrontabSchedule.Parse(cron); + _nextScheduleRun = _schedule.GetNextOccurrence(DateTime.Now); + + _cancellationToken = new CancellationToken(); + } + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + Log.Information("MaidBot Scheduler Hosted Service is starting."); + _cancellationToken = cancellationToken; + try + { + do + { + if (_apiConfiguration.FeatureFlags.RunScheduler && DateTime.Now > _nextScheduleRun) + { + using var scope = _scopeFactory.CreateScope(); + await Task.Run(async () => await scope.ServiceProvider.GetRequiredService().HandleLogDistribution()); + + _nextScheduleRun = _schedule.GetNextOccurrence(DateTime.Now); + } + + await Task.Delay(5000, cancellationToken); //5 seconds delay + } while (!cancellationToken.IsCancellationRequested); + } + catch (TaskCanceledException taskCanceledException) when (_cancellationToken.IsCancellationRequested) + { + Log.Information(taskCanceledException, "MaidBot Scheduler Hosted Service was shut down normally."); + } + catch (Exception exception) + { + Log.Error(exception, "Error trying to startup main thread for MaidBot Scheduler Hosted Service"); + } + + Log.Information("MaidBot Scheduler Hosted Service is stopping."); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj new file mode 100644 index 0000000..a075066 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.csproj @@ -0,0 +1,47 @@ + + + + net8.0 + InProcess + 1.0.0 + 1.0.0 + + + + ..\LCU.API.Internal.MaidBotApi\LCU.Api.Internal.MaidBotApi.xml + 1701;1702;1591 + + + + ..\LCU.API.Internal.MaidBotApi\LCU.Api.Internal.MaidBotApi.xml + + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.xml b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.xml new file mode 100644 index 0000000..d9c5851 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi.xml @@ -0,0 +1,17 @@ + + + + LCU.Api.Internal.MaidBotApi + + + + If an entity cannot be found, that specific error can allow for a 404 or 400 with more detail to be + returned. So specify that to the API layer. + + + Do not want to expose database and related exceptions to the controllers / web layer. + The lower layers log what happened for developers, then return a general error; unless + a more specific error can be returned in a way to allow the client to act (such as NotFound). + + + diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Program.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Program.cs new file mode 100644 index 0000000..1156807 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Program.cs @@ -0,0 +1,207 @@ +using System; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.EntityFrameworkCore; +using Microsoft.OpenApi.Models; +using Microsoft.Extensions.Hosting; +using Newtonsoft.Json; +using MassTransit; +using Serilog; +using LCU.API.Internal.MaidBotApi.HostedService; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotApi.EnvironmentView; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Api.Internal.MaidBotLib.Persistence; +using LCU.Library.Internal.LcuMassTransitModels; +using LCU.Library.Internal.LcuMassTransit; +using LCU.Api.Internal.MaidBotApi.Consumers; +using LCU.Api.Internal.MaidBotApi.Configurations; +using LCU.Library.Internal.Logging.Models; +using LCU.Library.Internal.Logging; +using LCU.Library.Internal.Logging.Middleware; +using LCU.Library.Internal.LcuHttpClient; +using LCU.Api.Internal.MaidBotApi.DataAccesses; +namespace LCU.API.Internal.MaidBot; + +public class Program +{ + static string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; + + public static void Main(string[] args) + { + var builder = BuildBuilder(args); + BuildServicesAndConfigurations(builder); + BuildAppAndRun(builder); + } + + private static WebApplicationBuilder BuildBuilder(string[] args) + { + var builder = WebApplication.CreateBuilder(args); + builder.Host.UseSerilog(); + builder.Configuration.AddJsonFile("/app/config/environment-appsettings/appsettings.json", optional: true, reloadOnChange: true); + builder.Configuration.AddJsonFile("/app/config/workload-appsettings/appsettings.json", optional: true, reloadOnChange: true); + builder.Configuration.AddJsonFile("/vault/secrets/maidbot-api-seq-api-key.json", optional: true, reloadOnChange: true); + builder.Configuration.AddJsonFile("/vault/secrets/maidbot-api-connection-configuration-password.json", optional: true, reloadOnChange: true); + builder.Configuration.AddJsonFile("/vault/secrets/maidbot-api-connection-configuration-username.json", optional: true, reloadOnChange: true); + builder.Configuration.AddJsonFile("/vault/secrets/maidbot-database-connection.json", optional: true, reloadOnChange: true); + return builder; + } + + static void BuildServicesAndConfigurations(WebApplicationBuilder builder) + { + var services = builder.Services; + var configuration = builder.Configuration; + services.AddControllers(); + // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle + services.AddEndpointsApiExplorer(); + services.AddSwaggerGen(); + + services.AddDbContext(options => + { + options.UseSqlServer(configuration.GetSection("Connections").GetSection("SQL").GetSection("MaidBotDB").Value); + }); + + services.AddHttpClient(); + services.AddLCUHttpServices(); + + //Configurations + var apiConfiguration = new ApiConfiguration(); + configuration.GetSection("Primary").Bind(apiConfiguration); + services.AddSingleton(apiConfiguration); + //debugging + Console.WriteLine(JsonConvert.SerializeObject(apiConfiguration)); + + var connectionConfiguration = MassTransitConfigurationSetUp.AddConnectionConfiguration(ref services, configuration); + //debugging + Console.WriteLine(JsonConvert.SerializeObject(connectionConfiguration)); + + var receiveEndpointConfiguration = new ReceiveEndpointConfiguration(); + receiveEndpointConfiguration = MassTransitConfigurationSetUp.GetReceiveEndpointConfiguration(configuration, "ReceiveEndpoint"); + services.AddSingleton(receiveEndpointConfiguration); + //debugging + Console.WriteLine(JsonConvert.SerializeObject(receiveEndpointConfiguration)); + + //EnvironmentView + services.AddScoped(); + + var loggerConfiguration = new LoggingConfiguration(apiConfiguration.AppName, + apiConfiguration.SeqApiKey, + apiConfiguration.SeqUrl); + var lcuLogging = new LcuLogging(loggerConfiguration); + lcuLogging.UseLcuLogging(); + + services.AddCors(options => + { + options.AddPolicy(MyAllowSpecificOrigins, + builder => + { + builder.WithOrigins( + apiConfiguration.CorsAllowedOrigins + ).AllowAnyHeader().AllowAnyMethod(); + }); + }); + + AddMaidBotServices(ref services); + AddMaidBotLib(ref services); + AddMaidBotDataAccesses(ref services); + AddMassTransitServices(ref services, connectionConfiguration, receiveEndpointConfiguration, apiConfiguration); + + // The Hosted + services.AddHostedService(); + + // Register the Swagger generator, defining 1 or more Swagger documents + services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = $"{apiConfiguration.AppName}", Version = "v1" }); }); + + services.Configure(options => + { + options.SuppressModelStateInvalidFilter = true; + }); + } + + static void AddMaidBotServices(ref IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + } + + static void AddMaidBotLib(ref IServiceCollection services) + { + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + } + + static void AddMaidBotDataAccesses(ref IServiceCollection services) + { + services.AddScoped(); + } + + static void AddMassTransitServices(ref IServiceCollection services, + ConnectionConfiguration connectionConfiguration, + ReceiveEndpointConfiguration receiveEndpointConfiguration, + ApiConfiguration apiConfiguration) + { + services.AddMassTransit(x => + { + x.AddConsumer(); + + x.UsingRabbitMq((context, cfg) => + { + cfg.Host(connectionConfiguration.HostUrl, "/", host => + { + host.Username(connectionConfiguration.UserName); + host.Password(connectionConfiguration.Password); + }); + cfg.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420)); + + if (apiConfiguration.FeatureFlags.LoggingEventConsumer) + { + cfg.ReceiveEndpoint(receiveEndpointConfiguration.ReceiveEndpoint, e => + { + e.ConfigureConsumer(context); + e.SetQuorumQueue(); + e.PrefetchCount = receiveEndpointConfiguration.PrefetchLimit; + e.UseTimeout(t => t.Timeout = TimeSpan.FromSeconds(420)); + }); + } + }); + }); + services.AddMassTransitHostedService(); + } + + static void BuildAppAndRun(WebApplicationBuilder builder) + { + var app = builder.Build(); + + // Configure the HTTP request pipeline. + if (app.Environment.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + + app.UseSwagger(); + app.UseSwaggerUI(c => c.SwaggerEndpoint("v1/swagger.json", "LCU.Api.Internal.MaidBotApi v1")); + app.UseMiddleware(); + app.UseSerilogRequestLogging(options => + { + options.EnrichDiagnosticContext = RequestResponseLoggingMiddleware.RequestDataParser.EnrichFromRequest; + }); + + app.UseRouting(); + app.UseCors(MyAllowSpecificOrigins); + app.UseHttpsRedirection(); + app.UseAuthorization(); + app.MapControllers(); + app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); + + app.Run(); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureActiveDirectoryOptions.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureActiveDirectoryOptions.cs new file mode 100644 index 0000000..cd17897 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureActiveDirectoryOptions.cs @@ -0,0 +1,13 @@ + +namespace LCU.API.Internal.MaidBot.Security +{ + public class AzureActiveDirectoryOptions + { + public string ClientId { get; set; } + public string ClientSecret { get; set; } + public string Instance { get; set; } + public string Domain { get; set; } + public string TenantId { get; set; } + public string ValidAudience { get; set; } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureAdServiceCollectionExtensions.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureAdServiceCollectionExtensions.cs new file mode 100644 index 0000000..28a2232 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Security/AzureAdServiceCollectionExtensions.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; + +namespace LCU.API.Internal.MaidBot.Security +{ + public static class AzureAdServiceCollectionExtensions + { + public static AuthenticationBuilder AddAzureAdBearer(this AuthenticationBuilder builder) + => builder.AddAzureAdBearer(_ => { }); + + public static AuthenticationBuilder AddAzureAdBearer(this AuthenticationBuilder builder, Action configureOptions) + { + builder.Services.Configure(configureOptions); + builder.Services.AddSingleton, ConfigureAzureOptions>(); + builder.AddJwtBearer(); + return builder; + } + + private class ConfigureAzureOptions : IConfigureNamedOptions + { + private readonly AzureActiveDirectoryOptions _azureOptions; + + public ConfigureAzureOptions(IOptions azureOptions) + { + _azureOptions = azureOptions.Value; + } + + public void Configure(string name, JwtBearerOptions options) + { + options.Audience = _azureOptions.ClientId; + options.Authority = $"{_azureOptions.Instance}{_azureOptions.TenantId}"; + + options.TokenValidationParameters = new TokenValidationParameters + { + ValidAudience = _azureOptions.ValidAudience + }; + } + + public void Configure(JwtBearerOptions options) + { + Configure(Options.DefaultName, options); + } + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/DebugEventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/DebugEventLogService.cs new file mode 100644 index 0000000..1970ac2 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/DebugEventLogService.cs @@ -0,0 +1,46 @@ +using System; +using System.Threading.Tasks; +using Serilog; +using LCU.Api.Internal.MaidBotApi.Exceptions; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Library.Internal.Exceptions; + +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class DebugEventLogService : IDebugEventLogService +{ + private readonly IDebugEventLogRepository _debugEventLogRepository; + private readonly IUnitOfWork _unitOfWork; + + public DebugEventLogService(IUnitOfWork unitOfWork, + IDebugEventLogRepository debugEventLogRepository) + { + _unitOfWork = unitOfWork; + _debugEventLogRepository = debugEventLogRepository; + } + + public async Task DebugEventLog(EventLog eventLog) + { + if (!string.IsNullOrEmpty(eventLog.DebugData)) + { + var debugEventLog = new DebugEventLog(eventLog); + await SaveAsync(debugEventLog); + } + } + + public async Task SaveAsync(DebugEventLog debugEventLog) + { + try + { + var result = await _debugEventLogRepository.AddAsync(debugEventLog); + await _unitOfWork.CompleteAsync(); + return result; + } + catch (Exception exception) + { + Log.Error(exception, $"Failure saving DebugEventLog."); + throw new ServiceException($"Failure saving DebugEventLog."); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/EventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/EventLogService.cs new file mode 100644 index 0000000..0e9d131 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/EventLogService.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Serilog; +using Newtonsoft.Json; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Library.Internal.Exceptions; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class EventLogService : IEventLogService +{ + private readonly IEventLogRepository _eventLogRepository; + private readonly IDebugEventLogService _debugEventLogService; + private readonly ILoggingMatrixService _loggingMatrixService; + private readonly IUnitOfWork _unitOfWork; + + public EventLogService(IEventLogRepository eventLogRepository, + IDebugEventLogService debugEventLogService, + ILoggingMatrixService loggingMatrixService, + IUnitOfWork unitOfWork) + { + _eventLogRepository = eventLogRepository; + _debugEventLogService = debugEventLogService; + _loggingMatrixService = loggingMatrixService; + _unitOfWork = unitOfWork; + } + + public async Task HandleIncomingEventLog(EventLog eventLog) + { + var loggingMatrixes = await _loggingMatrixService.GetByApplicationLevelAndGroupAsync(eventLog.Application, + eventLog.Level, + eventLog.Group); + if (loggingMatrixes.Any()) + { + await SaveAsync(eventLog); + } + + await _debugEventLogService.DebugEventLog(eventLog); + } + + public async Task> GetAsync() + { + try + { + return await _eventLogRepository.ListAsync(); + } + catch (Exception exception) + { + var message = "Failure retrieving EventLogs."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}. "); + } + } + + public async Task SaveAsync(EventLog eventLog) + { + try + { + var result = await _eventLogRepository.AddAsync(eventLog); + await _unitOfWork.CompleteAsync(); + return result; + } + catch (Exception exception) + { + var message = $"Failure saving EventLog. EventLog: { JsonConvert.SerializeObject(eventLog)}"; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}."); + } + } + + public void DeleteMany(List eventLogs) + { + try + { + _eventLogRepository.RemoveRange(eventLogs); + _unitOfWork.Complete(); + } + catch (Exception exception) + { + var message = $"Failure to delete EventLogs."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}."); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IDebugEventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IDebugEventLogService.cs new file mode 100644 index 0000000..af9c550 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IDebugEventLogService.cs @@ -0,0 +1,9 @@ +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotLib.Models; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public interface IDebugEventLogService +{ + Task DebugEventLog(EventLog eventLog); + Task SaveAsync(DebugEventLog debugEventLog); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IEventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IEventLogService.cs new file mode 100644 index 0000000..f80b0d6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IEventLogService.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotLib.Models; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public interface IEventLogService +{ + Task HandleIncomingEventLog(EventLog eventLog); + Task> GetAsync(); + Task SaveAsync(EventLog eventLog); + void DeleteMany(List eventLogs); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILogDistributionService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILogDistributionService.cs new file mode 100644 index 0000000..029d1ad --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILogDistributionService.cs @@ -0,0 +1,7 @@ +using System.Threading.Tasks; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public interface ILogDistributionService +{ + Task HandleLogDistribution(); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILoggingMatrixService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILoggingMatrixService.cs new file mode 100644 index 0000000..2a57fcc --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/ILoggingMatrixService.cs @@ -0,0 +1,17 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotApi.Services +{ + public interface ILoggingMatrixService + { + Task> GetAsync(); + Task> GetActiveAsync(); + Task GetByIdAsync(int id); + Task> GetByApplicationLevelAndGroupAsync(string application, string level, string group); + Task> GetByApplicationAndLevelAsync(string application, string level); + Task SaveAsync(LoggingMatrix loggingMatrix); + Task UpdateAsync(LoggingMatrix loggingMatrix); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/INotificationsApiService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/INotificationsApiService.cs new file mode 100644 index 0000000..ce7bf37 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/INotificationsApiService.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotLib.Models; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public interface INotificationsApiService +{ + Task SendNotificationAsync(LoggingMatrix loggingMatrix, List eventLogs); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IQueueEventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IQueueEventLogService.cs new file mode 100644 index 0000000..9ec6885 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/IQueueEventLogService.cs @@ -0,0 +1,8 @@ +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotLib.Models; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public interface IQueueEventLogService +{ + Task QueueEventLog(EventLog request); +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LogDistributionService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LogDistributionService.cs new file mode 100644 index 0000000..318b6a8 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LogDistributionService.cs @@ -0,0 +1,59 @@ +using Serilog; +using System; +using System.Linq; +using System.Threading.Tasks; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class LogDistributionService : ILogDistributionService +{ + private readonly IEventLogService _eventLogService; + private readonly ILoggingMatrixService _loggingMatrixService; + private readonly INotificationsApiService _notificationsApiService; + + public LogDistributionService(IEventLogService eventLogService, + ILoggingMatrixService loggingMatrixService, + INotificationsApiService notificationsApiService) + { + _eventLogService = eventLogService; + _loggingMatrixService = loggingMatrixService; + _notificationsApiService = notificationsApiService; + } + + public async Task HandleLogDistribution() + { + try + { + var eventLogs = await _eventLogService.GetAsync(); + if(eventLogs == null || !eventLogs.Any()) + { + return; + } + + var loggingMatrixs = await _loggingMatrixService.GetActiveAsync(); + if (loggingMatrixs == null || !loggingMatrixs.Any()) + { + return; + } + + foreach (var loggingMatrix in loggingMatrixs) + { + var matrixEventLogs = eventLogs.Where(eventLog => eventLog.Application == loggingMatrix.Application && + eventLog.Level == loggingMatrix.Level && + eventLog.Group == loggingMatrix.Group).ToList(); + + if (!matrixEventLogs.Any()) + { + continue; + } + + await _notificationsApiService.SendNotificationAsync(loggingMatrix, matrixEventLogs); + } + + _eventLogService.DeleteMany(eventLogs.ToList()); + } + catch (Exception exception) + { + Log.Error(exception, "Failure to Handle Log Distribution."); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LoggingMatrixService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LoggingMatrixService.cs new file mode 100644 index 0000000..9c649af --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/LoggingMatrixService.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Serilog; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Library.Internal.Exceptions; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class LoggingMatrixService : ILoggingMatrixService +{ + private readonly ILoggingMatrixRepository _loggingMatrixRepository; + private readonly IUnitOfWork _unitOfWork; + + public LoggingMatrixService(IUnitOfWork unitOfWork, + ILoggingMatrixRepository loggingMatrixRepository) + { + _unitOfWork = unitOfWork; + _loggingMatrixRepository = loggingMatrixRepository; + } + + public async Task> GetAsync() + { + try + { + return await _loggingMatrixRepository.ListAsync(); + } + catch (Exception exception) + { + var message = "Failure retrieving Logging Matrixes."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}. "); + } + } + + public async Task> GetActiveAsync() + { + try + { + return await _loggingMatrixRepository.ListActiveAsync(); + } + catch (Exception exception) + { + var message = "Failure retrieving active Logging Matrixes."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}. "); + } + } + + public async Task> GetByApplicationLevelAndGroupAsync(string application, string level, string group) + { + try + { + return await _loggingMatrixRepository.RetrieveByApplicationLevelAndGroup(application, level, group); + } + catch (Exception exception) + { + var message = $"Failure retrieving Logging Matrixes with application {application} and level {level}."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}. "); + } + } + + public async Task> GetByApplicationAndLevelAsync(string application, string level) + { + try + { + return await _loggingMatrixRepository.RetrieveByApplciationAndLevel(application, level); + } + catch (Exception exception) + { + var message = $"Failure retrieving Logging Matrixes with application {application} and level {level}."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}. "); + } + } + + public async Task GetByIdAsync(int id) + { + LoggingMatrix loggingMatrix = null; + try + { + loggingMatrix = await _loggingMatrixRepository.FindByIdAsync(id); + return loggingMatrix; + } + catch (Exception exception) + { + var message = $"Failure retrieving Logging Matrix with id {id}."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}."); + } + } + + public async Task SaveAsync(LoggingMatrix loggingMatrix) + { + try + { + var result = await _loggingMatrixRepository.AddAsync(loggingMatrix); + await _unitOfWork.CompleteAsync(); + + return result; + } + catch (Exception exception) + { + var message = $"Failure saving Logging Matrix. LoggingMatrix: { JsonConvert.SerializeObject(loggingMatrix)}"; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}."); + } + } + + public async Task UpdateAsync(LoggingMatrix loggingMatrix) + { + try + { + var existing = await GetByIdAsync(loggingMatrix.LoggingMatrixId); + if (existing == null) + { + return null; + } + + existing.Application = loggingMatrix.Application; + existing.Level = loggingMatrix.Level; + existing.Group = loggingMatrix.Group; + existing.Email = loggingMatrix.Email; + existing.Disabled = loggingMatrix.Disabled; + + _loggingMatrixRepository.Update(existing); + await _unitOfWork.CompleteAsync(); + + return existing; + } + catch (Exception exception) + { + var message = $"Failure updating Logging Matrix. LoggingMatrix: { JsonConvert.SerializeObject(loggingMatrix)}"; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}."); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/NotificationsApiService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/NotificationsApiService.cs new file mode 100644 index 0000000..abc6286 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/NotificationsApiService.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Text; +using System.IO; +using Serilog; +using LCU.Api.Internal.MaidBotApi.DataAccesses; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Library.Internal.Exceptions; +using LCU.Shared.Common.NotificationApiLib.Models; +using LCU.Api.Internal.MaidBotApi.Configurations; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class NotificationsApiService : INotificationsApiService +{ + private readonly ApiConfiguration _apiConfiguration; + private readonly INotificationsApiDao _notificationsApiDao; + private const string TableRowsTag = "{TableRows}"; + private const string ApplicationTag = "{Application}"; + private const string LevelTag = "{Level}"; + + public NotificationsApiService(ApiConfiguration apiConfiguration, + INotificationsApiDao notificationsApiDao) + { + _apiConfiguration = apiConfiguration; + _notificationsApiDao = notificationsApiDao; + } + + public async Task SendNotificationAsync(LoggingMatrix loggingMatrix, List eventLogs) + { + try + { + var emailRequest = new EmailRequest + { + Recipient = new List { loggingMatrix.Email }, + Subject = $"{loggingMatrix.Application} - {loggingMatrix.Level}", + Body = CreateEmailBody(loggingMatrix, eventLogs) + }; + await _notificationsApiDao.SendEmailRequest(emailRequest); + } + catch (Exception exception) + { + var message = $"Failure to Send Maidbot Email."; + Log.Error(exception, message); + throw new ServiceException($"{message} Exception Message: {exception.Message}"); + } + } + + public string CreateEmailBody(LoggingMatrix loggingMatrix, List eventLogs) + { + var errorRows = new StringBuilder(); + foreach(var eventLog in eventLogs) + { + errorRows.Append(CreateEventLogRow(eventLog)); + } + + var logEmailTemplateReader = new StreamReader(_apiConfiguration.LogEmailTemplate); + string logEmailTemplateOutput = logEmailTemplateReader.ReadToEnd(); + logEmailTemplateOutput = logEmailTemplateOutput.Replace(TableRowsTag, errorRows.ToString()); + logEmailTemplateOutput = logEmailTemplateOutput.Replace(ApplicationTag, loggingMatrix.Level); + return logEmailTemplateOutput.Replace(LevelTag, loggingMatrix.Application); + } + + public string CreateEventLogRow(EventLog eventLog) + { + var errorRowReader = new StreamReader(_apiConfiguration.LogEmailRowTemplate); + string errorRowOutput = errorRowReader.ReadToEnd(); + + foreach (var property in eventLog.GetType().GetProperties()) + { + string value = property.GetValue(eventLog) == null ? string.Empty : + property.GetValue(eventLog).ToString(); + errorRowOutput = errorRowOutput.Replace($"{{{property.Name}}}", value); + } + + return errorRowOutput; + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/QueueEventLogService.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/QueueEventLogService.cs new file mode 100644 index 0000000..52fdc8b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Services/QueueEventLogService.cs @@ -0,0 +1,36 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using MassTransit; +using Serilog; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Library.Internal.Exceptions; +using LCU.Library.Internal.LcuMassTransitModels; +namespace LCU.Api.Internal.MaidBotApi.Services; + +public class QueueEventLogService : IQueueEventLogService +{ + private readonly ISendEndpoint _sendEndpoint; + + public QueueEventLogService(IBusControl busControl, + ReceiveEndpointConfiguration receiveEndpointConfiguration) + { + _sendEndpoint = busControl.GetSendEndpoint(receiveEndpointConfiguration.ReceiveEndpointUri).Result; + } + + public async Task QueueEventLog(EventLog request) + { + try + { + var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + await _sendEndpoint.Send(request, cancellationTokenSource.Token); + } + catch (Exception exception) + { + Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), + Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) + .Fatal(exception, "Failed to Queue EventLog Request."); + throw new ServiceException("Failed to Queue EventLog Request."); + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailRowTemplate.html b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailRowTemplate.html new file mode 100644 index 0000000..12f04f4 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailRowTemplate.html @@ -0,0 +1,4 @@ + + {LogTimeStamp} + {Message} + \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailTemplate.html b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailTemplate.html new file mode 100644 index 0000000..b7491cb --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/Templates/LogEmailTemplate.html @@ -0,0 +1,56 @@ + + + + + + + MaidBot: {Application} Event Logs + + +

MaidBot: {Application} {Level} Event Logs

+ + + + + + + + + {TableRows} + +
TimestampLog Details
+ + + \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/appsettings.json b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/appsettings.json new file mode 100644 index 0000000..819b651 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotApi/appsettings.json @@ -0,0 +1,38 @@ +{ + "Primary": { + "AppName": "MaidBot Api", + "SeqUrl": "http://localhost:5080", + "SeqApiKey": "VALUE-IN-KEYVAULT", + "NotificationsApiEmail": "https://localhost:50353/api/Email", + "FeatureFlags": { + "LoggingEventConsumer": true, + "RunScheduler": true + }, + "BatchSchedulerCron": "*/5 * * * *", + "CorsAllowedOrigins": [ + "http://localhost:3000", + "http://lcu-internal.com", + "https://lcu-internal.com", + "https://qa-api.lcu-internal.com", + "https://uat-api.lcu-internal.com", + "https://api.lcu-internal.com" + ], + "LogEmailTemplate": "./Templates/LogEmailTemplate.html", + "LogEmailRowTemplate": "./Templates/LogEmailRowTemplate.html" + }, + "ConnectionConfiguration": { + "HostUrl": "localhost", + "UserName": "guest", + "Password": "guest" + }, + "ReceiveEndpoint": { + "ReceiveEndpoint": "LCU.MaidBot", + "ReceiveEndpointType": "exchange", + "PrefetchLimit": 1 + }, + "Connections": { + "SQL": { + "MaidBotDB": "data source=localhost;initial catalog=MaidBot;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework" + } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/LCU.Api.Internal.MaidBotLib.csproj b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/LCU.Api.Internal.MaidBotLib.csproj new file mode 100644 index 0000000..0c94c02 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/LCU.Api.Internal.MaidBotLib.csproj @@ -0,0 +1,25 @@ + + + + netstandard2.0 + true + 1.0.2 + + 1.0.0 - Initial Creation + 1.0.1 - Add BusinessOperations Group Enum + 1.0.2 - Add IndirectLending Group Enum + + + 1.0.0 - Initial Creation + 1.0.1 - Add BusinessOperations Group Enum + 1.0.2 - Add IndirectLending Group Enum + + + + + + + + + + diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/DebugEventLog.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/DebugEventLog.cs new file mode 100644 index 0000000..ed66bb0 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/DebugEventLog.cs @@ -0,0 +1,20 @@ +namespace LCU.Api.Internal.MaidBotLib.Models +{ + public class DebugEventLog + { + public const int DebugMaxLength = 3000; + + public DebugEventLog() + { + + } + + public DebugEventLog(EventLog eventLog) + { + RawLog = eventLog.DebugData.Length > DebugMaxLength ? eventLog.DebugData.Substring(0, DebugMaxLength) : eventLog.DebugData; + } + + public int DebugEventLogId { get; set; } + public string RawLog { get; set; } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/EventLog.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/EventLog.cs new file mode 100644 index 0000000..d4c2fd4 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/EventLog.cs @@ -0,0 +1,16 @@ +using System; + +namespace LCU.Api.Internal.MaidBotLib.Models +{ + public class EventLog + { + public int EventLogId { get; set; } + public string Application { get; set; } + public string Level { get; set; } + public string Group { get; set; } + public DateTime LogTimeStamp { get; set; } + public string Message { get; set; } + public string Environment { get; set; } + public string DebugData { get; set; } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/GroupEnum.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/GroupEnum.cs new file mode 100644 index 0000000..c0790da --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/GroupEnum.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace LCU.Api.Internal.MaidBotLib.Models +{ + public enum GroupEnum + { + Testing, + ITDevelopment, + BusinessOperations, + IndirectLending + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/LoggingMatrix.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/LoggingMatrix.cs new file mode 100644 index 0000000..1b29cae --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/LoggingMatrix.cs @@ -0,0 +1,18 @@ +using System.ComponentModel.DataAnnotations; + +namespace LCU.Api.Internal.MaidBotLib.Models +{ + public class LoggingMatrix + { + public int LoggingMatrixId { get; set; } + [StringLength(200, MinimumLength = 1, ErrorMessage = "Application field must have a length between 1 and 200 characters")] + public string Application { get; set; } + [StringLength(50, MinimumLength = 1, ErrorMessage = "Level field must have a length between 1 and 50 characters")] + public string Level { get; set; } + [StringLength(100, MinimumLength = 1, ErrorMessage = "Groups field must have a length between 1 and 100 characters")] + public string Group { get; set; } + [StringLength(100, MinimumLength = 1, ErrorMessage = "Emails field must have a length between 1 and 100 characters")] + public string Email { get; set; } + public bool Disabled { get; set; } + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/PropertyEnum.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/PropertyEnum.cs new file mode 100644 index 0000000..e8d816c --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Models/PropertyEnum.cs @@ -0,0 +1,7 @@ +namespace LCU.Api.Internal.MaidBotLib.Models +{ + public enum PropertyEnum + { + Group + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Persistence/AppDbContext.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Persistence/AppDbContext.cs new file mode 100644 index 0000000..cc2f8e4 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Persistence/AppDbContext.cs @@ -0,0 +1,23 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using Microsoft.EntityFrameworkCore; + +namespace LCU.Api.Internal.MaidBotLib.Persistence +{ + public class AppDbContext : DbContext + { + public DbSet LoggingMatrixs { get; set; } + public DbSet EventLogs { get; set; } + public DbSet DebugEventLogs { get; set; } + + public AppDbContext(DbContextOptions options) : base(options) { } + + protected override void OnModelCreating(ModelBuilder builder) + { + base.OnModelCreating(builder); + + builder.Entity().ToTable("LoggingMatrix"); + builder.Entity().ToTable("EventLog"); + builder.Entity().ToTable("DebugEventLog"); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/BaseRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/BaseRepository.cs new file mode 100644 index 0000000..aa18938 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/BaseRepository.cs @@ -0,0 +1,17 @@ +using LCU.Api.Internal.MaidBotLib.Persistence; +using System; +using System.Collections.Generic; +using System.Text; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public abstract class BaseRepository + { + protected readonly AppDbContext _context; + + public BaseRepository(AppDbContext context) + { + _context = context; + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/DebugEventLogRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/DebugEventLogRepository.cs new file mode 100644 index 0000000..c75bbae --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/DebugEventLogRepository.cs @@ -0,0 +1,20 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Persistence; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public class DebugEventLogRepository : BaseRepository, IDebugEventLogRepository + { + public DebugEventLogRepository(AppDbContext context) : base(context) { } + + public async Task AddAsync(DebugEventLog debugEventLog) + { + var result = await _context.DebugEventLogs.AddAsync(debugEventLog); + return result.Entity; + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/EventLogRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/EventLogRepository.cs new file mode 100644 index 0000000..72bd32f --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/EventLogRepository.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Persistence; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public class EventLogRepository : BaseRepository, IEventLogRepository + { + public EventLogRepository(AppDbContext context) : base(context) { } + + public async Task> ListAsync() + { + return await _context.EventLogs.ToListAsync(); + } + + public async Task AddAsync(EventLog eventLog) + { + var result = await _context.EventLogs.AddAsync(eventLog); + return result.Entity; + } + + public void RemoveRange(List eventLog) + { + _context.EventLogs.RemoveRange(eventLog); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IDebugEventLogRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IDebugEventLogRepository.cs new file mode 100644 index 0000000..fb59f6b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IDebugEventLogRepository.cs @@ -0,0 +1,13 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public interface IDebugEventLogRepository + { + Task AddAsync(DebugEventLog debugEventLog); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IEventLogRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IEventLogRepository.cs new file mode 100644 index 0000000..61c5941 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IEventLogRepository.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using LCU.Api.Internal.MaidBotLib.Models; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public interface IEventLogRepository + { + Task> ListAsync(); + Task AddAsync(EventLog eventLog); + void RemoveRange(List eventLog); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/ILoggingMatrixRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/ILoggingMatrixRepository.cs new file mode 100644 index 0000000..b100338 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/ILoggingMatrixRepository.cs @@ -0,0 +1,19 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public interface ILoggingMatrixRepository + { + Task> ListAsync(); + Task> ListActiveAsync(); + Task FindByIdAsync(int id); + Task> RetrieveByApplicationLevelAndGroup(string application, string level, string group); + Task> RetrieveByApplciationAndLevel(string application, string level); + Task AddAsync(LoggingMatrix loggingMatrix); + void Update(LoggingMatrix loggingMatrix); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IUnitOfWork.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IUnitOfWork.cs new file mode 100644 index 0000000..971d35d --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/IUnitOfWork.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public interface IUnitOfWork + { + Task CompleteAsync(); + void Complete(); + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/LoggingMatrixRepository.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/LoggingMatrixRepository.cs new file mode 100644 index 0000000..67cc084 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/LoggingMatrixRepository.cs @@ -0,0 +1,59 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Persistence; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public class LoggingMatrixRepository : BaseRepository, ILoggingMatrixRepository + { + public LoggingMatrixRepository(AppDbContext context) : base(context) { } + + public async Task> ListAsync() + { + return await _context.LoggingMatrixs.ToListAsync(); + } + + public async Task> ListActiveAsync() + { + return await _context.LoggingMatrixs.Where(loggingMatrix => !loggingMatrix.Disabled).ToListAsync(); + } + + public async Task FindByIdAsync(int id) + { + return await _context.LoggingMatrixs.Where(loggingMatrix => loggingMatrix.LoggingMatrixId == id).FirstOrDefaultAsync(); + } + + public async Task> RetrieveByApplicationLevelAndGroup(string application, string level, string group) + { + return await _context.LoggingMatrixs + .Where(matrix => matrix.Application == application && + matrix.Level == level && + matrix.Group == group && + !matrix.Disabled) + .ToListAsync(); + } + + public async Task> RetrieveByApplciationAndLevel(string application, string level) + { + return await _context.LoggingMatrixs + .Where(matrix => matrix.Application == application && + matrix.Level == level && + !matrix.Disabled) + .ToListAsync(); + } + + public async Task AddAsync(LoggingMatrix loggingMatrix) + { + var result = await _context.LoggingMatrixs.AddAsync(loggingMatrix); + return result.Entity; + } + + public void Update(LoggingMatrix loggingMatrix) + { + _context.LoggingMatrixs.Update(loggingMatrix); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/UnitOfWork.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/UnitOfWork.cs new file mode 100644 index 0000000..dbc8666 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotLib/Repositories/UnitOfWork.cs @@ -0,0 +1,25 @@ +using LCU.Api.Internal.MaidBotLib.Persistence; +using System.Threading.Tasks; + +namespace LCU.Api.Internal.MaidBotLib.Repositories +{ + public class UnitOfWork : IUnitOfWork + { + private readonly AppDbContext _context; + + public UnitOfWork(AppDbContext context) + { + _context = context; + } + + public async Task CompleteAsync() + { + await _context.SaveChangesAsync(); + } + + public void Complete() + { + _context.SaveChanges(); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/LCU.Api.Internal.MaidBotSeqApp.csproj b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/LCU.Api.Internal.MaidBotSeqApp.csproj new file mode 100644 index 0000000..ca15570 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/LCU.Api.Internal.MaidBotSeqApp.csproj @@ -0,0 +1,42 @@ + + + + netstandard2.0 + true + LCU.Api.Internal.MaidBotSeqApp + 1.0.0 + Always + + + + + + + + + + + + + + $(TargetsForTfmSpecificBuildOutput);CopyProjectReferencesToPackage + + + + + + <_ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->WithMetadataValue('ReferenceSourceTarget', 'ProjectReference')->WithMetadataValue('PrivateAssets', 'All'))" /> + + + + + + + + + + + + + + diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/SeqToRabbit.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/SeqToRabbit.cs new file mode 100644 index 0000000..56eaff1 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSeqApp/SeqToRabbit.cs @@ -0,0 +1,100 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using Newtonsoft.Json; +using Seq.Apps; +using Seq.Apps.LogEvents; +using System; +using System.Net.Http; +using System.Text; + +namespace LCU.Api.Internal.MaidBotSeqApp +{ + /// + /// Queues LogEvent. + /// + [SeqApp("QueueLogs", Description = "This will queue logs based on a signal event")] + public class SeqToRabbit : SeqApp, ISubscribeTo + { + private static readonly HttpClient _client = new HttpClient(); + + [SeqAppSetting(DisplayName = "Url", HelpText = "Url of MaidBot")] + public string Url { get; set; } + [SeqAppSetting(DisplayName = "DebugMode", HelpText = "Setting this will set DebugData field to the events serialized object and save to our DebugEventLog database table.")] + public bool DebugMode { get; set; } + + protected override void OnAttached() + { + base.OnAttached(); + } + + // Called by Seq whenever an event is sent to the app + public void On(Event evt) + { + EventLog logRequest = CreateLogRequest(evt); + + if(logRequest == null) + { + return; + } + + QueueLogEvent(logRequest); + } + + public bool MissingRequiredFields(Event evt) + { + return evt == null || + evt.Data == null || + evt.Data.RenderedMessage == null || + evt.Data.Properties == null || + !evt.Data.Properties.ContainsKey("Application") || + !evt.Data.Properties.ContainsKey("Group"); + } + + public EventLog CreateLogRequest(Event evt) + { + var eventLog = new EventLog(); + + try + { + if (MissingRequiredFields(evt)) + { + Log.Debug("Seq LogEventData missing required fields to be logged by MaidBot."); + return null; + } + + eventLog.Application = evt.Data.Properties["Application"].ToString(); + eventLog.Level = Enum.GetName(typeof(LogEventLevel), evt.Data.Level); + eventLog.LogTimeStamp = evt.TimestampUtc; + eventLog.Message = evt.Data.RenderedMessage; + eventLog.Group = evt.Data.Properties["Group"].ToString(); + eventLog.Environment = evt.Data.Properties.ContainsKey("Environment") ? evt.Data.Properties["Environment"].ToString() : ""; + eventLog.DebugData = DebugMode ? JsonConvert.SerializeObject(evt) : ""; + + return eventLog; + } + catch(Exception ex) + { + Log.Debug(ex, "[Error] MaidBot: Error Creating Event Log."); + return null; + } + } + + public void QueueLogEvent(EventLog eventLog) + { + try + { + var encodedContent = JsonConvert.SerializeObject(eventLog); + var content = new StringContent(encodedContent, Encoding.UTF8, "application/json"); + HttpResponseMessage response = _client.PostAsync(Url, content).Result; + + if (!response.IsSuccessStatusCode) + { + Log.Debug("[Error] Failure to send Event Log to MaidBot."); + } + } + catch(Exception ex) + { + Log.Debug(ex, "[Error] MaidBot: Failure to send Event Log to MaidBot."); + } + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/DebugEventLog.sql b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/DebugEventLog.sql new file mode 100644 index 0000000..fa0f260 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/DebugEventLog.sql @@ -0,0 +1,5 @@ +CREATE TABLE [dbo].[DebugEventLog] +( + [DebugEventLogId] INT NOT NULL PRIMARY KEY IDENTITY, + [RawLog] VARCHAR(3000) NULL +) diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/EventLog.sql b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/EventLog.sql new file mode 100644 index 0000000..10f9024 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/EventLog.sql @@ -0,0 +1,11 @@ +CREATE TABLE [dbo].[EventLog] +( + [EventLogId] INT NOT NULL PRIMARY KEY IDENTITY, + [Application] VARCHAR(500) NOT NULL, + [Level] VARCHAR(100) NOT NULL, + [Group] VARCHAR(200) NOT NULL, + [LogTimeStamp] DATETIME NOT NULL, + [Message] VARCHAR(MAX) NOT NULL, + [Environment] VARCHAR(100) NOT NULL, + [DebugData] VARCHAR(MAX) NULL +) diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.refactorlog b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.refactorlog new file mode 100644 index 0000000..ef19c82 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.refactorlog @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.sqlproj b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.sqlproj new file mode 100644 index 0000000..e6a9124 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.sqlproj @@ -0,0 +1,68 @@ + + + + Debug + AnyCPU + LCU.Api.Internal.MaidBotSql + 2.0 + 4.1 + {ecce6677-a2f2-4694-964f-f91ebe7aac00} + Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider + Database + + + LCU.Api.Internal.MaidBotSql + LCU.Api.Internal.MaidBotSql + 1033, CI + BySchemaAndSchemaType + True + v4.5 + CS + Properties + False + True + True + + + bin\Release\ + $(MSBuildProjectName).sql + False + pdbonly + true + false + true + prompt + 4 + + + bin\Debug\ + $(MSBuildProjectName).sql + false + true + full + false + true + true + prompt + 4 + + + 11.0 + + True + 11.0 + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LoggingMatrix.sql b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LoggingMatrix.sql new file mode 100644 index 0000000..195e850 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotSql/LoggingMatrix.sql @@ -0,0 +1,9 @@ +CREATE TABLE [dbo].[LoggingMatrix] +( + [LoggingMatrixId] INT NOT NULL PRIMARY KEY IDENTITY, + [Application] VARCHAR(200) NOT NULL, + [Level] VARCHAR(50) NOT NULL, + [Group] VARCHAR(100) NOT NULL, + [Email] VARCHAR(100) NOT NULL, + [Disabled] BIT NULL +) diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/LoggingMatrixControllerTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/LoggingMatrixControllerTest.cs new file mode 100644 index 0000000..5659785 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/LoggingMatrixControllerTest.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.API.Internal.MaidBotApi.Controllers; +namespace LCU.Api.Internal.MaidBotTests.ControllerTests; + +public class LoggingMatrixControllerTest +{ + private readonly LoggingMatrixController _loggingMatrixController; + private readonly Mock _mockLoggingMatrixService; + + public LoggingMatrixControllerTest() + { + _mockLoggingMatrixService = new Mock(); + _loggingMatrixController = new LoggingMatrixController(_mockLoggingMatrixService.Object); + } + + [Fact] + public async void GetAllLoggingMatrix_Success_200() + { + // Arrange + _mockLoggingMatrixService.Setup(service => service.GetAsync()).ReturnsAsync(new List + { + new LoggingMatrix(), + new LoggingMatrix() + }); + + // Act + var result = await _loggingMatrixController.Get(); + + // Assert + Assert.NotNull(result); + + var okResult = result as OkObjectResult; + Assert.NotNull(okResult); + Assert.NotNull(okResult.Value); + + var extractedValue = okResult.Value as IEnumerable; + Assert.NotNull(extractedValue); + Assert.Equal(2, extractedValue.Count()); + } + + [Fact] + public async void GetAllLoggingMatrix_BsaCorrectionServiceThrowsError_500() + { + // Arrange + _mockLoggingMatrixService.Setup(service => service.GetAsync()).ThrowsAsync(new Exception()); + + // Act + var result = await _loggingMatrixController.Get(); + + // Assert + Assert.NotNull(result); + + var okResult = result as StatusCodeResult; + Assert.NotNull(okResult); + Assert.Equal(StatusCodes.Status500InternalServerError, okResult.StatusCode); + } + + [Fact] + public async void PostLoggingMatrix_LoggingMatrixReturnsNull_BadRequest400() + { + var loggingMatrix = new LoggingMatrix() { }; + _mockLoggingMatrixService.Setup(service => service.SaveAsync(loggingMatrix)).ReturnsAsync(() => null); + + // Act + var result = await _loggingMatrixController.Post(loggingMatrix); + + // Assert + Assert.NotNull(result); + + var okResult = result as ObjectResult; + Assert.NotNull(okResult); + Assert.Equal(StatusCodes.Status400BadRequest, okResult.StatusCode); + } + + [Fact] + public async void PostLoggingMatrix_throwsException_500() + { + var loggingMatrix = new LoggingMatrix() { }; + _mockLoggingMatrixService.Setup(service => service.SaveAsync(loggingMatrix)).Throws(new Exception("Exception from unit test")); + + // Act + var result = await _loggingMatrixController.Post(loggingMatrix); + + // Assert + Assert.NotNull(result); + + var okResult = result as StatusCodeResult; + Assert.NotNull(okResult); + Assert.Equal(StatusCodes.Status500InternalServerError, okResult.StatusCode); + } + + [Fact] + public async void PutLoggingMatrix_BadRequestIdEqualZero_400() + { + var loggingMatrix = new LoggingMatrix + { + LoggingMatrixId = 0 + }; + + // Act + var result = await _loggingMatrixController.Put(loggingMatrix); + + // Assert + Assert.NotNull(result); + + var returnedResult = result as BadRequestObjectResult; + Assert.NotNull(returnedResult); + Assert.Equal(StatusCodes.Status400BadRequest, returnedResult.StatusCode); + } + + [Fact] + public async void PutLoggingMatrix_ThrowsException_500() + { + var loggingMatrix = new LoggingMatrix + { + LoggingMatrixId = 1 + }; + _mockLoggingMatrixService.Setup(service => service.UpdateAsync(loggingMatrix)).Throws(new Exception("Exception from update unit test")); + + // Act + var result = await _loggingMatrixController.Put(loggingMatrix); + + // Assert + Assert.NotNull(result); + + var okResult = result as StatusCodeResult; + Assert.NotNull(okResult); + Assert.Equal(StatusCodes.Status500InternalServerError, okResult.StatusCode); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/QueueEventLogControllerTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/QueueEventLogControllerTest.cs new file mode 100644 index 0000000..4737e5a --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ControllerTests/QueueEventLogControllerTest.cs @@ -0,0 +1,39 @@ +using System; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.API.Internal.MaidBotApi.Controllers; +namespace LCU.Api.Internal.MaidBotTests.ControllerTests; + +public class QueueEventLogControllerTest +{ + private readonly QueueEventLogController _queueEventLogController; + private readonly Mock _mockQueueEventLogService; + + public QueueEventLogControllerTest() + { + _mockQueueEventLogService = new Mock(); + _queueEventLogController = new QueueEventLogController(_mockQueueEventLogService.Object); + } + + [Fact] + public async Task PostLoggingMatrix_throwsException_500() + { + var eventLog = new EventLog() { }; + _mockQueueEventLogService.Setup(service => service.QueueEventLog(eventLog)).Throws(new Exception("Exception from unit test")); + + // Act + var result = await _queueEventLogController.Post(eventLog); + + // Assert + Assert.NotNull(result); + + var okResult = result as StatusCodeResult; + Assert.NotNull(okResult); + Assert.Equal(StatusCodes.Status500InternalServerError, okResult.StatusCode); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/LCU.Api.Internal.MaidBotTests.csproj b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/LCU.Api.Internal.MaidBotTests.csproj new file mode 100644 index 0000000..2b96559 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/LCU.Api.Internal.MaidBotTests.csproj @@ -0,0 +1,27 @@ + + + + net8.0 + + false + + + + + + + + + + + + + + + + + Always + + + + diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ModelTest/DebugEventLogTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ModelTest/DebugEventLogTest.cs new file mode 100644 index 0000000..ce1de53 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ModelTest/DebugEventLogTest.cs @@ -0,0 +1,21 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using Xunit; + +namespace LCU.Api.Internal.MaidBotTests.ModelTest +{ + public class DebugEventLogTests + { + [Fact] + public void CreateDebugEventLog_RawLog_LengthToLong_TrimToMax() + { + // Arrange / Act + var testEventLog = new EventLog(); + testEventLog.DebugData = "TESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETETESTTESTETSETETSETSETSETSETSETSETSETETESTSETSETSETSETSETESTESTESTSETSETSETSETSTESTETEETE"; + var debugEventLog = new DebugEventLog(testEventLog); + + // Assert + Assert.NotNull(debugEventLog); + Assert.Equal(DebugEventLog.DebugMaxLength, debugEventLog.RawLog.Length); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/DbContextFromJson.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/DbContextFromJson.cs new file mode 100644 index 0000000..353cae7 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/DbContextFromJson.cs @@ -0,0 +1,70 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Persistence; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace LCU.Api.Internal.MaidBotTests.RepositoryTests +{ + public class DbContextTestSet + { + public IReadOnlyCollection LoggingMatrixSet { get; set; } + } + + public abstract class DbContextFromJsonTest + { + public DbContextTestSet GetTestAccounts(string filePath) + { + var testSet = new DbContextTestSet(); + + // Get the absolute path to the JSON file + var path = Path.IsPathRooted(filePath) + ? filePath + : Path.GetRelativePath(Directory.GetCurrentDirectory(), filePath); + + if (!File.Exists(path)) + { + throw new ArgumentException($"Could not find file at path: {path}"); + } + + var fileData = File.ReadAllText(filePath); + var allData = JObject.Parse(fileData); + + var runInfo = allData["LoggingMatrixs"]; + testSet.LoggingMatrixSet = runInfo?.ToObject>(); + + return testSet; + } + + public AppDbContext GetBlankContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .Options; + return new AppDbContext(options); + } + + public AppDbContext GetContextWithData(string jsonFileName) + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .Options; + var context = new AppDbContext(options); + + var testData = GetTestAccounts(jsonFileName); + AddTo(context.LoggingMatrixs, testData.LoggingMatrixSet); + + context.SaveChanges(); + + return context; + } + + private static void AddTo(DbSet collection, IEnumerable range) where T : class + { + if (range != null) collection.AddRange(range); + } + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixRepositoryTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixRepositoryTest.cs new file mode 100644 index 0000000..8709a49 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixRepositoryTest.cs @@ -0,0 +1,66 @@ +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Xunit; + +namespace LCU.Api.Internal.MaidBotTests.RepositoryTests +{ + public class LoggingMatrixRepositoryTest : DbContextFromJsonTest + { + private readonly LoggingMatrixRepository _loggingMatrixRepository; + private const string JsonTestDataFilePath = "RepositoryTests\\LoggingMatrixTestData.json"; + + public LoggingMatrixRepositoryTest() + { + var dbContext = GetContextWithData(JsonTestDataFilePath); + _loggingMatrixRepository = new LoggingMatrixRepository(dbContext); + } + + //TODO: These UnitTest have been commented out since there is version mismatch and at this time + // we are not going to undergo the work that is required to upgrade. The work to upgrade + // the .net version will need to be done in a separate Story: + // 89988 Maidbot API > Library Modernization + // https://landmarkcu.visualstudio.com/LMCU/_boards/board/t/Development/Stories?workitem=89988. + // This decision was made during this PR: + // https://landmarkcu.visualstudio.com/Platform/_git/LCU.API.Internal.MaidBotApi/pullrequest/17634 + //[Fact] + //public void ListAsync_Test() + //{ + // var loggingMatrixes = _loggingMatrixRepository.ListAsync().Result; + // Assert.NotNull(loggingMatrixes); + // Assert.Equal(6, loggingMatrixes.Count()); + //} + + //[Fact] + //public async void FindById_Test() + //{ + // var loggingMatrix = await _loggingMatrixRepository.FindByIdAsync(1); + // Assert.NotNull(loggingMatrix); + // Assert.Equal(1, loggingMatrix.LoggingMatrixId); + //} + + //[Fact] + //public void RetrieveByApplicationLevelAndGroup_Test() + //{ + // var application = "Test App 1"; + // var group = "Test Group 1"; + // var level = "Test Level 1"; + // var loggingMatrixes = _loggingMatrixRepository.RetrieveByApplicationLevelAndGroup(application, level, group ).Result; + // Assert.NotNull(loggingMatrixes); + // Assert.Equal(2, loggingMatrixes.Count()); + //} + + //[Fact] + //public void RetrieveByApplciationAndLevel_Test() + //{ + // var application = "Test App 1"; + // var level = "Test Level 1"; + // var loggingMatrixes = _loggingMatrixRepository.RetrieveByApplciationAndLevel(application, level).Result; + // Assert.NotNull(loggingMatrixes); + // Assert.Equal(3, loggingMatrixes.Count()); + //} + } +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixTestData.json b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixTestData.json new file mode 100644 index 0000000..d52898d --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/RepositoryTests/LoggingMatrixTestData.json @@ -0,0 +1,52 @@ +{ + "LoggingMatrixs": [ + { + "LoggingmatrixId": 1, + "Application": "Test App 1", + "Level": "Test Level 1", + "Group": "Test Group 1", + "Email": "TestEmail1@Landmarkcu.com", + "Disabled": false + }, + { + "LoggingmatrixId": 2, + "Application": "Test App 2", + "Level": "Test Level 2", + "Group": "Test Group 2", + "Email": "TestEmail2@Landmarkcu.com", + "Disabled": false + }, + { + "LoggingmatrixId": 3, + "Application": "Test App 3", + "Level": "Test Level 3", + "Group": "Test Group 3", + "Email": "TestEmail3@Landmarkcu.com", + "Disabled": true + }, + { + "LoggingmatrixId": 4, + "Application": "Test App 1", + "Level": "Test Level 1", + "Group": "Test Group 1", + "Email": "TestEmail4@Landmarkcu.com", + "Disabled": false + }, + { + "LoggingmatrixId": 5, + "Application": "Test App 1", + "Level": "Test Level 1", + "Group": "Test Group 1", + "Email": "TestEmail5@Landmarkcu.com", + "Disabled": true + }, + { + "LoggingmatrixId": 6, + "Application": "Test App 1", + "Level": "Test Level 1", + "Group": "Test Group 6", + "Email": "TestEmail6@Landmarkcu.com", + "Disabled": false + } + ] +} diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/DebugEventLogServiceTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/DebugEventLogServiceTest.cs new file mode 100644 index 0000000..e413c2d --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/DebugEventLogServiceTest.cs @@ -0,0 +1,85 @@ +using System; +using System.Threading.Tasks; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Exceptions; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Library.Internal.Exceptions; + +namespace LCU.Api.Internal.MaidBotTests.ServiceTests; + +public class DebugEventLogServiceTest +{ + private readonly DebugEventLogService _debugEventLogService; + private readonly Mock _mockDebugEventLogRepository; + + public DebugEventLogServiceTest() + { + var mockUnitOfWork = new Mock(); + _mockDebugEventLogRepository = new Mock(); + _debugEventLogService = new DebugEventLogService(mockUnitOfWork.Object, _mockDebugEventLogRepository.Object); + } + + [Fact] + public async Task SaveAsync_Success() + { + // Arrange + _mockDebugEventLogRepository.Setup(repo => repo.AddAsync(It.IsAny())).ReturnsAsync(new DebugEventLog()); + + // Act + var result = await _debugEventLogService.SaveAsync(new DebugEventLog()); + + // Assert + Assert.NotNull(result); + } + + [Fact] + public async Task SaveAsync_Exception_Throws_ServerError() + { + // Arrange + _mockDebugEventLogRepository.Setup(repo => repo.AddAsync(It.IsAny())).ThrowsAsync(new Exception()); + + // Act / Assert + await Assert.ThrowsAsync(async () => + await _debugEventLogService.SaveAsync(new DebugEventLog())); + } + + [Fact] + public async Task DebugEventLog_Verify_AddAsyncCalled_Once() + { + // Arrange + var testEventLog = new EventLog() + { + DebugData = "Test Debug Data" + }; + var testDebugEventLog = new DebugEventLog() + { + RawLog = "Test Debug Data" + }; + + _mockDebugEventLogRepository.Setup(repo => repo.AddAsync(testDebugEventLog)).ReturnsAsync(testDebugEventLog); + + //Act + await _debugEventLogService.DebugEventLog(testEventLog); + + //Assert + _mockDebugEventLogRepository.Verify(x => x.AddAsync(It.IsAny()), Times.Once); + } + + [Fact] + public async Task DebugEventLog_Verify_AddAsyncCalled_Never() + { + // Arrange + var testEventLog = new EventLog() { }; + _mockDebugEventLogRepository.Setup(repo => repo.AddAsync(It.IsAny())).ReturnsAsync(new DebugEventLog()); + var testDebugEventLog = new DebugEventLog(); + + //Act + await _debugEventLogService.DebugEventLog(testEventLog); + + //Assert + _mockDebugEventLogRepository.Verify(x => x.AddAsync(testDebugEventLog), Times.Never); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/EventLogServiceTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/EventLogServiceTest.cs new file mode 100644 index 0000000..ade374a --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/EventLogServiceTest.cs @@ -0,0 +1,170 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +namespace LCU.Api.Internal.MaidBotTests.ServiceTests; + +public class EventLogServiceTest +{ + private EventLogService _eventLogService; + private readonly Mock _mockEventLogRepository; + private readonly Mock _mockDebugEventLogService; + private readonly Mock _mockLoggingMatrixService; + private readonly Mock _mockUnitOfWork; + + public EventLogServiceTest() + { + _mockEventLogRepository = new Mock(); + _mockDebugEventLogService = new Mock(); + _mockLoggingMatrixService = new Mock(); + _mockUnitOfWork = new Mock(); + + _eventLogService = new EventLogService(_mockEventLogRepository.Object, + _mockDebugEventLogService.Object, + _mockLoggingMatrixService.Object, + _mockUnitOfWork.Object); + } + + [Fact] + public async Task HandleEventLog_AllMethods_Called_Once() + { + // Arrange + var testEventLog = new EventLog + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = "Test Debug Data" + }; + + var testLoggingMatrix = new List + { + new LoggingMatrix + { + LoggingMatrixId = 1, + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + Email = "TestEmail@Landmarkcu.com", + Disabled = false + } + }; + + _mockLoggingMatrixService.Setup(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), It.IsAny(), It.IsAny())).ReturnsAsync(testLoggingMatrix); + + var eventLogResult = new EventLog + { + EventLogId = 1, + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = "Test Debug Data" + }; + _mockEventLogRepository.Setup(x => x.AddAsync(It.IsAny())).ReturnsAsync(eventLogResult); + _mockDebugEventLogService.Setup(x => x.DebugEventLog(It.IsAny())); + + //Act + await _eventLogService.HandleIncomingEventLog(testEventLog); + + //Assert + _mockLoggingMatrixService.Verify(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _mockEventLogRepository.Verify(x => x.AddAsync(It.IsAny()), Times.Once); + _mockDebugEventLogService.Verify(x => x.DebugEventLog(It.IsAny()), Times.Once); + } + + [Fact] + public async Task HandleEventLog_NoMatrixFound_EventLogNotSaved() + { + // Arrange + var testEventLog = new EventLog() + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = null + }; + + var testLoggingMatrix = new List(); + _mockLoggingMatrixService.Setup(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(testLoggingMatrix); + + var eventLogResult = new EventLog + { + EventLogId = 1, + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = null + }; + _mockEventLogRepository.Setup(x => x.AddAsync(It.IsAny())).ReturnsAsync(eventLogResult); + _mockDebugEventLogService.Setup(x => x.DebugEventLog(It.IsAny())); + + //Act + await _eventLogService.HandleIncomingEventLog(testEventLog); + + //Assert + _mockLoggingMatrixService.Verify(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _mockEventLogRepository.Verify(x => x.AddAsync(It.IsAny()), Times.Never); + _mockDebugEventLogService.Verify(x => x.DebugEventLog(It.IsAny()), Times.Once); + } + + [Fact] + public async Task HandleEventLog_NoMatrixFound_EventLogNotSaved_DebugSaved() + { + // Arrange + var testEventLog = new EventLog() + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = "Test Debug Data" + }; + + var testLoggingMatrix = new List(); + _mockLoggingMatrixService.Setup(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), + It.IsAny(), + It.IsAny())).ReturnsAsync(testLoggingMatrix); + + var eventLogResult = new EventLog + { + EventLogId = 1, + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2020"), + Message = "Test Message", + Environment = "Test", + DebugData = "Test Debug Data" + }; + _mockEventLogRepository.Setup(x => x.AddAsync(It.IsAny())).ReturnsAsync(eventLogResult); + _mockDebugEventLogService.Setup(x => x.DebugEventLog(It.IsAny())); + + //Act + await _eventLogService.HandleIncomingEventLog(testEventLog); + + //Assert + _mockLoggingMatrixService.Verify(x => x.GetByApplicationLevelAndGroupAsync(It.IsAny(), It.IsAny(), It.IsAny()), Times.Once); + _mockEventLogRepository.Verify(x => x.AddAsync(It.IsAny()), Times.Never); + _mockDebugEventLogService.Verify(x => x.DebugEventLog(It.IsAny()), Times.Once); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LogDistributionServiceTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LogDistributionServiceTest.cs new file mode 100644 index 0000000..1b81ee1 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LogDistributionServiceTest.cs @@ -0,0 +1,130 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +namespace LCU.Api.Internal.MaidBotTests.ServiceTests; + +public class LogDistributionServiceTest +{ + private LogDistributionService _logDistributionService; + private readonly Mock _mockEventLogService; + private readonly Mock _mockLoggingMatrixService; + private readonly Mock _notificationsApiService; + + public LogDistributionServiceTest() + { + _mockEventLogService = new Mock(); + _mockLoggingMatrixService = new Mock(); + _notificationsApiService = new Mock(); + + _logDistributionService = new LogDistributionService(_mockEventLogService.Object, + _mockLoggingMatrixService.Object, + _notificationsApiService.Object); + } + + [Fact] + public async Task HandleLogDistribution_NoEventLogs() + { + var eventLogs = new List(); + _mockEventLogService.Setup(x => x.GetAsync()).ReturnsAsync(eventLogs); + + await _logDistributionService.HandleLogDistribution(); + + _mockEventLogService.Verify(x => x.GetAsync(), Times.Once); + _mockLoggingMatrixService.Verify(x => x.GetActiveAsync(), Times.Never); + _notificationsApiService.Verify(x => x.SendNotificationAsync(It.IsAny(), It.IsAny>()), Times.Never); + _mockEventLogService.Verify(x => x.DeleteMany(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task HandleLogDistribution_EventLogs_NoMatrix() + { + var eventLogs = new List + { + new EventLog + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2022"), + Message = "Test Message 1", + Environment = "Test", + DebugData = "Test Debug Data" + }, + new EventLog + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2022"), + Message = "Test Message 2", + Environment = "Test", + DebugData = "Test Debug Data" + } + }; + _mockEventLogService.Setup(x => x.GetAsync()).ReturnsAsync(eventLogs); + + var loggingMatrixs = new List(); + _mockLoggingMatrixService.Setup(x => x.GetActiveAsync()).ReturnsAsync(loggingMatrixs); + + await _logDistributionService.HandleLogDistribution(); + + _mockEventLogService.Verify(x => x.GetAsync(), Times.Once); + _mockLoggingMatrixService.Verify(x => x.GetActiveAsync(), Times.Once); + _notificationsApiService.Verify(x => x.SendNotificationAsync(It.IsAny(), It.IsAny>()), Times.Never); + _mockEventLogService.Verify(x => x.DeleteMany(It.IsAny>()), Times.Never); + } + + [Fact] + public async Task HandleLogDistribution_EventLogs_LoggingMatrix_SendEmail() + { + var eventLogs = new List + { + new EventLog + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2022"), + Message = "Test Message 1", + Environment = "Test", + DebugData = "Test Debug Data" + }, + new EventLog + { + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + LogTimeStamp = Convert.ToDateTime("1/1/2022"), + Message = "Test Message 2", + Environment = "Test", + DebugData = "Test Debug Data" + } + }; + _mockEventLogService.Setup(x => x.GetAsync()).ReturnsAsync(eventLogs); + + var loggingMatrixs = new List + { + new LoggingMatrix + { + LoggingMatrixId = 1, + Application = "Test App", + Level = "Test Level", + Group = "Test Group", + Email = "TestEmail@Landmarkcu.com", + Disabled = false + } + }; + _mockLoggingMatrixService.Setup(x => x.GetActiveAsync()).ReturnsAsync(loggingMatrixs); + + await _logDistributionService.HandleLogDistribution(); + + _mockEventLogService.Verify(x => x.GetAsync(), Times.Once); + _mockLoggingMatrixService.Verify(x => x.GetActiveAsync(), Times.Once); + _notificationsApiService.Verify(x => x.SendNotificationAsync(It.IsAny(), It.IsAny>()), Times.Once); + _mockEventLogService.Verify(x => x.DeleteMany(It.IsAny>()), Times.Once); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LoggingMatrixServiceTest.cs b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LoggingMatrixServiceTest.cs new file mode 100644 index 0000000..a616de6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/ServiceTests/LoggingMatrixServiceTest.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Moq; +using Xunit; +using LCU.Api.Internal.MaidBotApi.Exceptions; +using LCU.Api.Internal.MaidBotApi.Services; +using LCU.Api.Internal.MaidBotLib.Models; +using LCU.Api.Internal.MaidBotLib.Repositories; +using LCU.Library.Internal.Exceptions; + +namespace LCU.Api.Internal.MaidBotTests.ServiceTests; + +public class LoggingMatrixServiceTest +{ + private readonly LoggingMatrixService _loggingMatrixService; + private readonly Mock _mockLoggingMatrixRepository; + + public LoggingMatrixServiceTest() + { + var mockUnitOfWork = new Mock(); + _mockLoggingMatrixRepository = new Mock(); + _loggingMatrixService = new LoggingMatrixService(mockUnitOfWork.Object, _mockLoggingMatrixRepository.Object); + } + + [Fact] + public async Task GetAsync_Success() + { + // Arrange + _mockLoggingMatrixRepository.Setup(repo => repo.ListAsync()).ReturnsAsync(new List() + { + new LoggingMatrix(), + new LoggingMatrix() + }); + + // Act + var result = await _loggingMatrixService.GetAsync(); + + // Assert + Assert.NotNull(result); + Assert.Equal(2, result.Count()); + } + + [Fact] + public async Task GetAsync_Exception_Throws_ServerError() + { + // Arrange + _mockLoggingMatrixRepository.Setup(repo => repo.ListAsync()).ThrowsAsync(new Exception()); + + // Act / Assert + await Assert.ThrowsAsync(async () => await _loggingMatrixService.GetAsync()); + } + + [Fact] + public async Task SaveAsync_Success() + { + // Arrange + _mockLoggingMatrixRepository.Setup(repo => repo.AddAsync(It.IsAny())).ReturnsAsync(new LoggingMatrix()); + + // Act + var result = await _loggingMatrixService.SaveAsync(new LoggingMatrix()); + + // Assert + Assert.NotNull(result); + } + + [Fact] + public async Task SaveAsync_Exception_Throws_ServerError() + { + // Arrange + _mockLoggingMatrixRepository.Setup(repo => repo.AddAsync(It.IsAny())).ThrowsAsync(new Exception()); + + // Act / Assert + await Assert.ThrowsAsync(async () => + await _loggingMatrixService.SaveAsync(new LoggingMatrix())); + } + + [Fact] + public async Task UpdateAsync_Success_Updates_Fields() + { + // Arrange + var testingLoggingMatrix = new LoggingMatrix() + { + LoggingMatrixId = 1, + Application = "Test Application", + Level = "Test Level", + Group = "Test Group", + Email = "TESTEmail@Landmarkcu.com", + Disabled = false + }; + _mockLoggingMatrixRepository.Setup(repo => repo.FindByIdAsync(It.IsAny())).ReturnsAsync(testingLoggingMatrix); + + // Act + var result = await _loggingMatrixService.UpdateAsync(testingLoggingMatrix); + + // Assert + Assert.NotNull(result); + Assert.Equal(testingLoggingMatrix.LoggingMatrixId, result.LoggingMatrixId); + Assert.Equal(testingLoggingMatrix.Application, result.Application); + Assert.Equal(testingLoggingMatrix.Level, result.Level); + Assert.Equal(testingLoggingMatrix.Group, result.Group); + Assert.Equal(testingLoggingMatrix.Email, result.Email); + Assert.Equal(testingLoggingMatrix.Disabled, result.Disabled); + } +} \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/additional_test_args.runsettings b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/additional_test_args.runsettings new file mode 100644 index 0000000..16d6a41 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/LCU.Api.Internal.MaidBotTests/additional_test_args.runsettings @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + .*microsoft.* + + + + + + + + + + + diff --git a/LCU.API.Internal.MaidBotApi/README.md b/LCU.API.Internal.MaidBotApi/README.md new file mode 100644 index 0000000..1bc32ad --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/README.md @@ -0,0 +1,41 @@ +# Introduction +Maidbot was created to give us the ability to get notifications on seq and other loggings. It has an api endpoint that can be used to queue a log. Once the log is consumed it queries our LoggingMatrix for the Application, Level, and Group. If a matrix is found the email is used to send a notification with the message of the log. + +# Seq Debugging +Since seq app can only be tested on seq, there is no way to debug locally. This adds a pain to testing the application. So if there is a need to test follow the following steps. + +Local MaidBotApi Steps. +1. Create your own test queue in QA Rabbit. Use the same exchange LCU.Logging.Direct and routing key for binding. +2. Change appsettings to use your test queue. + +Seq App Steps +1. Make code adjustments to SeqToRabbit. +2. Build +3. Grab nuget package from bin. +4. Change name of nuget to indicate it is for debugging. +5. Go to QA server and to the seq nuget folder. (Currently C:\Program Files\Seq\Nuget) +6. Add nuget file +7. Go to QA seq --> settings --> Apps --> Install From Nuget +8. Select "LocalMachine" as Feed. +9. Add your test nuget package name and put as Package Id. (Doesn't require package version). +10. Install. +11. Add Instance +12. Create a Title that indicates that it is Debuging/Testing. +13. Add Stream that you wish to use to test. NOTE: Do not use information or other logging that occurs very frequently. If there is an issue with your app it will flood seq with errors. +14. Add QA MaidBotApi url +15. Select DebugMode to indicate that the raw log will be saved to our MaidBot DebugEventLog table. +16. DO NOT select "Run the app on existing events" as this can cause a flood logs. (Unless fully aware what you are pulling in). +17. Save Changes + + +#App Integration Steps +- Pull LCU.Api.Internal.MaidBotLib Nuget into project. +- Add Context of desired property such as Group. + - Log.ForContext(Enum.GetName(typeof(PropertyEnum), PropertyEnum.Group), + Enum.GetName(typeof(GroupEnum), GroupEnum.ITDevelopment)) + .Fatal("Failure return status, message: {0} {1}", e.Message, e.StackTrace); +- Use MaidBotApi swagger to create matrix to follow your app, desired level, and group. +- In Seq create signal that will capture this log(If not already created). +- Create instance that will watch this signal. + + diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-k8s-pipeline.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-k8s-pipeline.yaml new file mode 100644 index 0000000..246e782 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-k8s-pipeline.yaml @@ -0,0 +1,74 @@ +parameters: +- name: target_environment + displayName: Target Environment + type: string + default: qa + values: + - qa + - uat + - prd +- name: k8s_namespace + displayName: K8s Namespace to deploy to + type: string + default: landmarkcu + values: + - landmarkcu + +variables: +- template: ./config-files/${{ parameters.target_environment }}-pvars.yaml +- name: source_branch_name + value: $[replace(replace(variables['Build.SourceBranch'], 'refs/heads/', ''), '/', '-')] +- name: docker_container_repository_name + value: landmarkcu/lcu.api.internal.maidbot-maidbot + +resources: + repositories: + - repository: azdo_pipeline_templates + type: git + name: Infrastructure Platform/azdo-pipeline-templates + ref: main + +stages: +# DOTNET BUILD AND NUGET PUSH +- template: dotnet-nuget-build-push.yaml@azdo_pipeline_templates + parameters: + azdo_agent_pool: $(pvar_azdo_agent_pool_nuget) + azure_artifacts_feed: 'LCU-Internal' + branches_to_push: + - develop + - main + +# DACPAC BUILD AND PUSH +- template: db-build-deploy.yaml@azdo_pipeline_templates + parameters: + azdo_agent_pool: $(pvar_azdo_agent_pool_db) + azdo_deployment_environment: $(pvar_azdo_deployment_environment_db) + sql_project_path: './LCU.API.Internal.MaidBotSql/LCU.API.Internal.MaidBotSql.sqlproj' + built_sql_dacpac_file_path: './LCU.API.Internal.MaidBotSql/bin/Release/LCU.API.Internal.MaidBotSql.dacpac' + name_of_artifact: LCU_API_Internal_MaidBotSql_dacpac + db_name: $(pvar_LCU_Api_Internal_MaidBotSql_db_name) + sql_server_name: $(pvar_LCU_Api_Internal_MaidBotSql_sql_server_name) + +# DOCKER BUILD AND PUSH +- template: docker-build-push.yaml@azdo_pipeline_templates + parameters: + azdo_agent_pool: $(pvar_azdo_agent_pool) + docker_registry_service_connection: $(pvar_docker_registry_service_connection) + docker_container_repository_name: $(docker_container_repository_name) + dockerfile_path: ./Dockerfile + docker_image_tags: | + build-$(Build.BuildId) + $(source_branch_name) + +# K8S DEPLOY +- template: k8s-deploy.yaml@azdo_pipeline_templates + parameters: + dependsOn: CI + condition: or(eq(variables['Build.SourceBranchName'], 'develop'), eq(variables['Build.SourceBranchName'], 'main')) + azdo_agent_pool: $(pvar_azdo_agent_pool) + kubectl_version: $(pvar_kubectl_version) + k8s_service_connection: $(pvar_k8s_service_connection) + k8s_namespace: ${{ parameters.k8s_namespace }} + k8s_kustomization_path: ./kustomize/overlays/${{ parameters.target_environment }} + docker_registry_service_connection: $(pvar_docker_registry_service_connection) + docker_image_to_deploy: $(docker_container_repository_name):build-$(Build.BuildId) diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-feature-branches.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-feature-branches.yaml new file mode 100644 index 0000000..ee44aef --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-feature-branches.yaml @@ -0,0 +1,10 @@ +trigger: + branches: + include: + - '*' + exclude: + - 'main' + - 'develop' +extends: + template: azure-k8s-pipeline.yaml + diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-prd.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-prd.yaml new file mode 100644 index 0000000..7d13684 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-prd.yaml @@ -0,0 +1,9 @@ +trigger: + branches: + include: + - 'main' +extends: + template: azure-k8s-pipeline.yaml + parameters: + target_environment: prd + k8s_namespace: landmarkcu diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-qa.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-qa.yaml new file mode 100644 index 0000000..f581dd4 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-qa.yaml @@ -0,0 +1,9 @@ +trigger: + branches: + include: + - 'develop' +extends: + template: azure-k8s-pipeline.yaml + parameters: + target_environment: qa + k8s_namespace: landmarkcu diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-uat.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-uat.yaml new file mode 100644 index 0000000..4747234 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/azure-pipelines-uat.yaml @@ -0,0 +1,9 @@ +trigger: + branches: + include: + - 'main' +extends: + template: azure-k8s-pipeline.yaml + parameters: + target_environment: uat + k8s_namespace: landmarkcu diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/prd-pvars.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/prd-pvars.yaml new file mode 100644 index 0000000..e6fe16b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/prd-pvars.yaml @@ -0,0 +1,12 @@ +--- +variables: + pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-prd-lz-uscz + pvar_docker_registry_service_connection: Docker Registry LMCU + pvar_k8s_service_connection: svcon-sub-df-lcu-apps-prd-aks-k8s-uscz + pvar_kubectl_version: 1.25.9 + pvar_azdo_agent_pool_nuget: LCUOnPrem + pvar_azdo_agent_pool_db: LCUOnPrem + pvar_azdo_deployment_environment_db: DB-PRD + + pvar_LCU_Api_Internal_MaidBotSql_db_name: MaidBot + pvar_LCU_Api_Internal_MaidBotSql_sql_server_name: D1CLS01P \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/qa-pvars.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/qa-pvars.yaml new file mode 100644 index 0000000..afbe508 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/qa-pvars.yaml @@ -0,0 +1,12 @@ +--- +variables: + pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-qa-lz-uscz + pvar_docker_registry_service_connection: Docker Registry LMCU + pvar_k8s_service_connection: svcon-sub-df-lcu-apps-qa-aks-k8s-uscz + pvar_kubectl_version: 1.25.9 + pvar_azdo_agent_pool_nuget: LCUOnPrem + pvar_azdo_agent_pool_db: LCUOnPrem + pvar_azdo_deployment_environment_db: DB-QA + + pvar_LCU_Api_Internal_MaidBotSql_db_name: MaidBot + pvar_LCU_Api_Internal_MaidBotSql_sql_server_name: DAZCDTBWEB01Q \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/uat-pvars.yaml b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/uat-pvars.yaml new file mode 100644 index 0000000..ff3441c --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azdo_pipelines/config-files/uat-pvars.yaml @@ -0,0 +1,12 @@ +--- +variables: + pvar_azdo_agent_pool: vmss-sub-df-lcu-apps-uat-lz-uscz + pvar_docker_registry_service_connection: Docker Registry LMCU + pvar_k8s_service_connection: svcon-sub-df-lcu-apps-uat-aks-k8s-uscz + pvar_kubectl_version: 1.25.9 + pvar_azdo_agent_pool_nuget: LCUOnPrem + pvar_azdo_agent_pool_db: LCUOnPrem + pvar_azdo_deployment_environment_db: DB-UAT + + pvar_LCU_Api_Internal_MaidBotSql_db_name: MaidBot + pvar_LCU_Api_Internal_MaidBotSql_sql_server_name: D1CLS01U \ No newline at end of file diff --git a/LCU.API.Internal.MaidBotApi/azure-pipelines.yml b/LCU.API.Internal.MaidBotApi/azure-pipelines.yml new file mode 100644 index 0000000..a33cdae --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/azure-pipelines.yml @@ -0,0 +1,79 @@ +# ASP.NET Core + +name: 'MaidBotAPI.$(Build.SourceBranchName).$(Date:yyyyMMdd)$(Rev:.r)' +trigger: + branches: + include: + - '*' + +pool: + name: LCUOnPrem + +variables: + buildConfiguration: 'Release' + +steps: +- task: DotNetCoreCLI@2 + inputs: + command: 'restore' + feedsToUse: 'select' + vstsFeed: '58ebbac4-8e98-4281-bb3f-58003852f4a7' + +- task: DotNetCoreCLI@2 + inputs: + command: 'build' + projects: '**/*.csproj' + arguments: '--configuration $(buildConfiguration)' + +- task: DotNetCoreCLI@2 + displayName: Test + inputs: + command: test + projects: '**/*.Tests.csproj' + arguments: '--configuration $(BuildConfiguration) --collect "Code coverage" --settings additional_test_args.runsettings' + +- task: DotNetCoreCLI@2 + displayName: 'dotnet publish $(buildConfiguration)' + inputs: + command: 'publish' + publishWebProjects: false + projects: '**/*.csproj' + arguments: '--configuration $(BuildConfiguration) --output $(Build.ArtifactStagingDirectory)' + +- task: CopyFiles@2 + displayName: Copy Nuget Package to artifact staging directory + inputs: + SourceFolder: './LCU.Api.Internal.MaidBotSeqApp/bin/$(BuildConfiguration)/' + Contents: '*.nupkg' + TargetFolder: '$(build.artifactstagingdirectory)' + OverWrite: true + +- task: NuGetCommand@2 + condition: and (succeeded(), or( eq(variables['Build.SourceBranchName'], 'develop'), eq(variables['Build.SourceBranchName'], 'main')) ) + displayName: 'NuGet push' + inputs: + command: push + packagesToPush: 'LCU.Api.Internal.MaidBotLib/bin/Release/*.nupkg' + publishVstsFeed: '58ebbac4-8e98-4281-bb3f-58003852f4a7' + allowPackageConflicts: true + +- task: MSBuild@1 + displayName: Build sql project + inputs: + solution: './LCU.Api.Internal.MaidBotSql/LCU.Api.Internal.MaidBotSql.sqlproj' + configuration: 'Release' + +- task: CopyFiles@2 + displayName: Copy dacpac to artifact staging directory + inputs: + SourceFolder: './LCU.Api.Internal.MaidBotSql/bin/$(BuildConfiguration)/' + Contents: 'LCU.Api.Internal.MaidBotSql.dacpac' + TargetFolder: '$(build.artifactstagingdirectory)' + OverWrite: true + +- task: PublishBuildArtifacts@1 + condition: and (succeeded(), or( eq(variables['Build.SourceBranchName'], 'develop'), eq(variables['Build.SourceBranchName'], 'main')) ) + displayName: 'Publish Artifact: dist' + inputs: + PathtoPublish: '$(build.artifactstagingdirectory)' + ArtifactName: 'dist' diff --git a/LCU.API.Internal.MaidBotApi/kustomize/base/Deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/base/Deployment.yaml new file mode 100644 index 0000000..3ed59bb --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/base/Deployment.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: maidbot-api +spec: + replicas: 1 + selector: + matchLabels: + app: maidbot-api + strategy: + rollingUpdate: + maxSurge: 25% + maxUnavailable: 25% + type: RollingUpdate + template: + metadata: + labels: + app: maidbot-api + spec: + volumes: [] + containers: + - name: maidbot-api + env: [] + volumeMounts: [] + image: maidbot-api + resources: + requests: + cpu: 50m + memory: 512Mi + limits: + memory: 512Mi + ports: + - containerPort: 8080 + livenessProbe: + initialDelaySeconds: 5 + periodSeconds: 5 + httpGet: + path: /api/status + port: 8080 + readinessProbe: + initialDelaySeconds: 5 + periodSeconds: 5 + httpGet: + path: /api/status + port: 8080 diff --git a/LCU.API.Internal.MaidBotApi/kustomize/base/Service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/base/Service.yaml new file mode 100644 index 0000000..05e2845 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/base/Service.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: v1 +kind: Service +metadata: + name: maidbot-api +spec: + selector: + app: maidbot-api + ports: + - port: 8080 + targetPort: 8080 diff --git a/LCU.API.Internal.MaidBotApi/kustomize/base/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/base/kustomization.yaml new file mode 100644 index 0000000..28e1ae0 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/base/kustomization.yaml @@ -0,0 +1,9 @@ +resources: + - Deployment.yaml + - Service.yaml + - virtual-service.yaml + - secrets-provider-class.yaml + +images: +- name: maidbot-api + newName: landmarkcu/lcu.api.internal.maidbot-maidbot diff --git a/LCU.API.Internal.MaidBotApi/kustomize/base/secrets-provider-class.yaml b/LCU.API.Internal.MaidBotApi/kustomize/base/secrets-provider-class.yaml new file mode 100644 index 0000000..e71a6dc --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/base/secrets-provider-class.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: maidbot-api-csi-key-vault-secrets-provider +spec: + provider: azure + parameters: + usePodIdentity: "false" + useVMManagedIdentity: "true" + tenantId: 63cd1554-2783-4a86-ae50-b9e6c21c9499 diff --git a/LCU.API.Internal.MaidBotApi/kustomize/base/virtual-service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/base/virtual-service.yaml new file mode 100644 index 0000000..21a360b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/base/virtual-service.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: maidbot-api +spec: + hosts: [] + gateways: + - istio-system/ingress-gateway + http: + - name: maidbot-api + match: + - uri: + prefix: / + route: + - destination: + host: maidbot-api + port: + number: 8080 diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/kustomization.yaml new file mode 100644 index 0000000..0ae1552 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/kustomization.yaml @@ -0,0 +1,10 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: + - target: + kind: Deployment + path: set_secrets_deployment.yaml + - target: + kind: SecretProviderClass + path: set_secrets_provider.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml new file mode 100644 index 0000000..fe741bf --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_deployment.yaml @@ -0,0 +1,41 @@ +- op: add + path: /spec/template/spec/volumes/- + value: + name: maidbot-api-secrets + csi: + driver: secrets-store.csi.k8s.io + readOnly: true + volumeAttributes: + secretProviderClass: normal-maidbot-api-csi-key-vault-secrets-provider + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: maidbot-api-secrets + mountPath: /vault/secrets/maidbot-api-seq-api-key.json + readOnly: true + subPath: maidbot-api-seq-api-key + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: maidbot-api-secrets + mountPath: /vault/secrets/maidbot-api-connection-configuration-password.json + readOnly: true + subPath: maidbot-api-connection-configuration-password + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: maidbot-api-secrets + mountPath: /vault/secrets/maidbot-api-connection-configuration-username.json + readOnly: true + subPath: maidbot-api-connection-configuration-username + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: maidbot-api-secrets + mountPath: /vault/secrets/maidbot-database-connection.json + readOnly: true + subPath: maidbot-database-connection diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_provider.yaml b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_provider.yaml new file mode 100644 index 0000000..a76ffb7 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/keyvaults/normal/set_secrets_provider.yaml @@ -0,0 +1,20 @@ +- op: add + path: /spec/parameters/objects + value: | + array: + - | + objectName: maidbot-api-seq-api-key + objectType: secret + objectVersion: "" + - | + objectName: maidbot-api-connection-configuration-password + objectType: secret + objectVersion: "" + - | + objectName: maidbot-api-connection-configuration-username + objectType: secret + objectVersion: "" + - | + objectName: maidbot-database-connection + objectType: secret + objectVersion: "" diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/appsettings/appsettings.json b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/appsettings/appsettings.json new file mode 100644 index 0000000..2c63c08 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/appsettings/appsettings.json @@ -0,0 +1,2 @@ +{ +} diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/kustomization.yaml new file mode 100644 index 0000000..43a2aa5 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/kustomization.yaml @@ -0,0 +1,40 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +#Test istio process +namePrefix: normal- + +configMapGenerator: + - name: maidbot-api-appsettings + files: + - appsettings/appsettings.json +generatorOptions: + disableNameSuffixHash: true + +patches: + - target: + kind: Deployment + path: set_appsettings_deployment.yaml + +replacements: + - source: + kind: Deployment + fieldPath: metadata.name + targets: + - select: + kind: Deployment + fieldPaths: + - spec.selector.matchLabels.app + - spec.template.metadata.labels.app + - spec.template.spec.containers.*.name + + - select: + kind: Service + fieldPaths: + - spec.selector.app + + - select: + kind: VirtualService + fieldPaths: + - spec.http.*.route.*.destination.host + - spec.http.*.name diff --git a/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/set_appsettings_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/set_appsettings_deployment.yaml new file mode 100644 index 0000000..c70222c --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/components/workloads/normal/set_appsettings_deployment.yaml @@ -0,0 +1,12 @@ +- op: add + path: /spec/template/spec/volumes/- + value: + name: volume-appsettings + configMap: + name: maidbot-api-appsettings + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: volume-appsettings + mountPath: /app/config/workload-appsettings diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/kustomization.yaml new file mode 100644 index 0000000..c70db7d --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/kustomization.yaml @@ -0,0 +1,8 @@ +resources: + - ../../../base +patchesStrategicMerge: + - set_appsettings_deployment.yaml + - set_secrets_provider_class.yaml +images: +- name: maidbot-api + newName: landmarkcu/lcu.api.internal.maidbot-maidbot diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_appsettings_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_appsettings_deployment.yaml new file mode 100644 index 0000000..1edd47a --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_appsettings_deployment.yaml @@ -0,0 +1,12 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: maidbot-api +spec: + template: + spec: + containers: + - name: maidbot-api + env: + - name: ASPNETCORE_ENVIRONMENT + value: "Development" diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_secrets_provider_class.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_secrets_provider_class.yaml new file mode 100644 index 0000000..2afb5ab --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/common/set_secrets_provider_class.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: secrets-store.csi.x-k8s.io/v1 +kind: SecretProviderClass +metadata: + name: maidbot-api-csi-key-vault-secrets-provider +spec: + parameters: + userAssignedIdentityID: 3286ed9a-f85c-4c50-b742-dbd3c1c3fe1f + keyvaultName: kv-lz-apps-qa-uscz diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/kustomization.yaml new file mode 100644 index 0000000..25a65b6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/kustomization.yaml @@ -0,0 +1,2 @@ +resources: + - normal diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/configmap.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/configmap.yaml new file mode 100644 index 0000000..d640e51 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/configmap.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: maidbot-configmap +data: + primary.json: | + { + "Primary": { + "SeqUrl": "https://qa-seq.lcu-internal.com", + "CorsAllowedOrigins": [ + "http://localhost:3000", + "http://lcu-internal.com", + "https://lcu-internal.com", + "https://qa-api.lcu-internal.com", + "https://uat-api.lcu-internal.com", + "https://api.lcu-internal.com" + ] + } + } diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/kustomization.yaml new file mode 100644 index 0000000..6dd0c3b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/kustomization.yaml @@ -0,0 +1,5 @@ +resources: + - configmap.yaml + - ../common +patchesStrategicMerge: + - set_virtual_service.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/set_virtual_service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/set_virtual_service.yaml new file mode 100644 index 0000000..4a1ea98 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/local/normal/set_virtual_service.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: networking.istio.io/v1beta1 +kind: VirtualService +metadata: + name: maidbot-api +spec: + hosts: + - qa-maidbot-api.apps.azure.lcu-internal.com diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/appsettings/appsettings.json b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/appsettings/appsettings.json new file mode 100644 index 0000000..420714f --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/appsettings/appsettings.json @@ -0,0 +1,27 @@ +{ + "Primary": { + "AppName": "MaidBot Api", + "SeqUrl": "https://seq.lcu-internal.com", + "NotificationsApiEmail": "https://notificationsapi.lcu-internal.com/api/Email", + "FeatureFlags": { + "LoggingEventConsumer": true, + "RunScheduler": true + }, + "BatchSchedulerCron": "*/5 * * * *", + "CorsAllowedOrigins": [ + "http://lcu-internal.com", + "https://lcu-internal.com", + "https://api.lcu-internal.com" + ], + "LogEmailTemplate": "./Templates/LogEmailTemplate.html", + "LogEmailRowTemplate": "./Templates/LogEmailRowTemplate.html" + }, + "ConnectionConfiguration": { + "HostUrl": "rabbitmq.lcu-internal.com" + }, + "ReceiveEndpoint": { + "ReceiveEndpoint": "LCU.MaidBot", + "ReceiveEndpointType": "exchange", + "PrefetchLimit": 1 + } +} diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/kustomization.yaml new file mode 100644 index 0000000..6e732a6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: + - target: + kind: SecretProviderClass + path: set_secrets_provider_class.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/set_secrets_provider_class.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/set_secrets_provider_class.yaml new file mode 100644 index 0000000..8719a77 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/component/set_secrets_provider_class.yaml @@ -0,0 +1,7 @@ +- op: add + path: /spec/parameters/userAssignedIdentityID + value: 3286ed9a-f85c-4c50-b742-dbd3c1c3fe1f + +- op: add + path: /spec/parameters/keyvaultName + value: kv-lz-apps-qa-uscz diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/kustomization.yaml new file mode 100644 index 0000000..651b146 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/kustomization.yaml @@ -0,0 +1,14 @@ +resources: + - normal + +configMapGenerator: + - name: maidbot-api-environment-appsettings + files: + - appsettings/appsettings.json +generatorOptions: + disableNameSuffixHash: true + +patches: + - target: + kind: Deployment + path: set_configmap_deployment.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/kustomization.yaml new file mode 100644 index 0000000..a1e6b06 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/kustomization.yaml @@ -0,0 +1,12 @@ +resources: + - ../../../base + +components: + - ../component + - ../../../components/keyvaults/normal + - ../../../components/workloads/normal + +patches: + - target: + kind: VirtualService + path: set_virtual_service.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/set_virtual_service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/set_virtual_service.yaml new file mode 100644 index 0000000..701049b --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/normal/set_virtual_service.yaml @@ -0,0 +1,3 @@ +- op: add + path: /spec/hosts/- + value: prd-maidbot-api.apps.azure.lcu-internal.com diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/set_configmap_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/set_configmap_deployment.yaml new file mode 100644 index 0000000..e37f2cd --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/prd/set_configmap_deployment.yaml @@ -0,0 +1,12 @@ +- op: add + path: /spec/template/spec/volumes/- + value: + name: volume-environment-appsettings + configMap: + name: maidbot-api-environment-appsettings + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: volume-environment-appsettings + mountPath: /app/config/environment-appsettings diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/appsettings/appsettings.json b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/appsettings/appsettings.json new file mode 100644 index 0000000..8baa159 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/appsettings/appsettings.json @@ -0,0 +1,27 @@ +{ + "Primary": { + "AppName": "MaidBot Api", + "SeqUrl": "https://qa-seq.lcu-internal.com", + "NotificationsApiEmail": "https://qa-notificationsapi.lcu-internal.com/api/Email", + "FeatureFlags": { + "LoggingEventConsumer": true, + "RunScheduler": true + }, + "BatchSchedulerCron": "*/5 * * * *", + "CorsAllowedOrigins": [ + "http://lcu-internal.com", + "https://lcu-internal.com", + "https://qa-api.lcu-internal.com" + ], + "LogEmailTemplate": "./Templates/LogEmailTemplate.html", + "LogEmailRowTemplate": "./Templates/LogEmailRowTemplate.html" + }, + "ConnectionConfiguration": { + "HostUrl": "qa-rabbitmq.lcu-internal.com" + }, + "ReceiveEndpoint": { + "ReceiveEndpoint": "LCU.MaidBot", + "ReceiveEndpointType": "exchange", + "PrefetchLimit": 1 + } +} diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/kustomization.yaml new file mode 100644 index 0000000..6e732a6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: + - target: + kind: SecretProviderClass + path: set_secrets_provider_class.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/set_secrets_provider_class.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/set_secrets_provider_class.yaml new file mode 100644 index 0000000..8719a77 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/component/set_secrets_provider_class.yaml @@ -0,0 +1,7 @@ +- op: add + path: /spec/parameters/userAssignedIdentityID + value: 3286ed9a-f85c-4c50-b742-dbd3c1c3fe1f + +- op: add + path: /spec/parameters/keyvaultName + value: kv-lz-apps-qa-uscz diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/kustomization.yaml new file mode 100644 index 0000000..651b146 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/kustomization.yaml @@ -0,0 +1,14 @@ +resources: + - normal + +configMapGenerator: + - name: maidbot-api-environment-appsettings + files: + - appsettings/appsettings.json +generatorOptions: + disableNameSuffixHash: true + +patches: + - target: + kind: Deployment + path: set_configmap_deployment.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/kustomization.yaml new file mode 100644 index 0000000..a1e6b06 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/kustomization.yaml @@ -0,0 +1,12 @@ +resources: + - ../../../base + +components: + - ../component + - ../../../components/keyvaults/normal + - ../../../components/workloads/normal + +patches: + - target: + kind: VirtualService + path: set_virtual_service.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/set_virtual_service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/set_virtual_service.yaml new file mode 100644 index 0000000..fc8ef51 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/normal/set_virtual_service.yaml @@ -0,0 +1,3 @@ +- op: add + path: /spec/hosts/- + value: qa-maidbot-api.apps.azure.lcu-internal.com diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/set_configmap_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/set_configmap_deployment.yaml new file mode 100644 index 0000000..e37f2cd --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/qa/set_configmap_deployment.yaml @@ -0,0 +1,12 @@ +- op: add + path: /spec/template/spec/volumes/- + value: + name: volume-environment-appsettings + configMap: + name: maidbot-api-environment-appsettings + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: volume-environment-appsettings + mountPath: /app/config/environment-appsettings diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/appsettings/appsettings.json b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/appsettings/appsettings.json new file mode 100644 index 0000000..63065c7 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/appsettings/appsettings.json @@ -0,0 +1,27 @@ +{ + "Primary": { + "AppName": "MaidBot Api", + "SeqUrl": "https://uat-seq.lcu-internal.com", + "NotificationsApiEmail": "https://uat-notificationsapi.lcu-internal.com/api/Email", + "FeatureFlags": { + "LoggingEventConsumer": true, + "RunScheduler": true + }, + "BatchSchedulerCron": "*/5 * * * *", + "CorsAllowedOrigins": [ + "http://lcu-internal.com", + "https://lcu-internal.com", + "https://uat-api.lcu-internal.com" + ], + "LogEmailTemplate": "./Templates/LogEmailTemplate.html", + "LogEmailRowTemplate": "./Templates/LogEmailRowTemplate.html" + }, + "ConnectionConfiguration": { + "HostUrl": "uat-rabbitmq.lcu-internal.com" + }, + "ReceiveEndpoint": { + "ReceiveEndpoint": "LCU.MaidBot", + "ReceiveEndpointType": "exchange", + "PrefetchLimit": 1 + } +} diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/kustomization.yaml new file mode 100644 index 0000000..6e732a6 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1alpha1 +kind: Component + +patches: + - target: + kind: SecretProviderClass + path: set_secrets_provider_class.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/set_secrets_provider_class.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/set_secrets_provider_class.yaml new file mode 100644 index 0000000..8719a77 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/component/set_secrets_provider_class.yaml @@ -0,0 +1,7 @@ +- op: add + path: /spec/parameters/userAssignedIdentityID + value: 3286ed9a-f85c-4c50-b742-dbd3c1c3fe1f + +- op: add + path: /spec/parameters/keyvaultName + value: kv-lz-apps-qa-uscz diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/kustomization.yaml new file mode 100644 index 0000000..651b146 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/kustomization.yaml @@ -0,0 +1,14 @@ +resources: + - normal + +configMapGenerator: + - name: maidbot-api-environment-appsettings + files: + - appsettings/appsettings.json +generatorOptions: + disableNameSuffixHash: true + +patches: + - target: + kind: Deployment + path: set_configmap_deployment.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/kustomization.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/kustomization.yaml new file mode 100644 index 0000000..a1e6b06 --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/kustomization.yaml @@ -0,0 +1,12 @@ +resources: + - ../../../base + +components: + - ../component + - ../../../components/keyvaults/normal + - ../../../components/workloads/normal + +patches: + - target: + kind: VirtualService + path: set_virtual_service.yaml diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/set_virtual_service.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/set_virtual_service.yaml new file mode 100644 index 0000000..637a66c --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/normal/set_virtual_service.yaml @@ -0,0 +1,3 @@ +- op: add + path: /spec/hosts/- + value: uat-maidbot-api.apps.azure.lcu-internal.com diff --git a/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/set_configmap_deployment.yaml b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/set_configmap_deployment.yaml new file mode 100644 index 0000000..e37f2cd --- /dev/null +++ b/LCU.API.Internal.MaidBotApi/kustomize/overlays/uat/set_configmap_deployment.yaml @@ -0,0 +1,12 @@ +- op: add + path: /spec/template/spec/volumes/- + value: + name: volume-environment-appsettings + configMap: + name: maidbot-api-environment-appsettings + +- op: add + path: /spec/template/spec/containers/0/volumeMounts/- + value: + name: volume-environment-appsettings + mountPath: /app/config/environment-appsettings